✔︎ 오늘의 정리
- API 요청하기
- URL의 구조
- Info.plist Default Configuration 오류
- Class 'MoreViewController' has no initializers 오류
- Pagenation
API 요청하기

이전에 만들어놨던 프로젝트에 카카오 책 검색 API를 추가하기 위해서 찾아보는데 저 --data-urlencode를 도통 어떻게 적용하는 건지 감이 오지 않았다,,,
같이 물음표로 넣나? 하고
https://dapi.kakao.com/v3/search/book?target=title?query=미움받을 용기
이런 식으로 넣어도 안 되고 ... ^_^
결국엔 네이버에 단어 검색해서 주소창에 어떻게 뜨는지 보고 대충 알았다

요기!
query는 &로 연결되어 있더라.

^_^ 최공
URL 주소의 구조
막상 바꿔서 해결이 되기는 했지만 왜 그렇게 되는지? 에 대해서 궁금해져서 좀 찾아보았다.
처음에는 queryStirng에서 ?와 &의 차이가 궁금해서 찾아보게 되었는데, 쭉쭉 타고 들어가다 보니 URL 주소의 구조와 https / http의 차이에 대해서도 알아보게 되었다.
본론으로 들어가 보자면... ...
일단, 우리가 서버와 통신을 통해 가져오는(글고 평소에 사용하는) url 주소는 이렇게 생겼다.

URL을 구성하는 종류에 대해서 알아보자면,
- protocol
- 컴퓨터끼리 네트워크 통신을 사용할 때의 규격을 말하며, HTTP와 HTTPS로 나뉜다. 둘의 차이는 보안의 차이이다. 실제로 HTTP 프로토콜과 HTTPS의 프로토콜의 규격은 동일하지만, 보안 인증서를 받은 웹 페이지만이 https 프로토콜에 속한다.
- http의 경우에는 이전 텍스트 기반의 웹 사이트에서 많이 사용되었으며, https의 경우에는 퍼블릭 키 암호화에 SSL 인증서를 사용하여 보안 기능을 제공하기 때문에, 최신 웹 사이트에서 주로 사용한다.
- 최근에는 웬만큼 큰 웹 사이트들은 http보다 https를 이용하고 있는데, 그 이유는 세 가지로 볼 수 있다.
- 보안: http의 경우에는 일반 텍스트로, 권한이 없는 사용자도 인터넷을 통해 쉽게 액세스하고 읽을 수 있따. 하지만, https는 도메인이나 URL을 제외한 모든 데이터(쿼리스트링, 파라미터(HTTP body)를 암호화된 형태로 전송하기 때문에 민감한 데이터를 전송할 때 좋다. 만약 결제 기능이나 송금 기능을 사용하는 웹 페이지라면 당연히! https를 선택하는 게 좋다.
- 권위: 검색 엔진의 경우, http의 신뢰성이 떨어지기 때문에 https 웹 페이지의 순위를 http 웹 페이지보다 높게 책정한다. 브라우저는 브라우저 주소 표시줄에서 웹 사이트 URL 옆에 있는 자물쇠 아이콘으로 사용자에게 https 연결을 보여주는데, 우리는 이를 통해 보안이 되고 있다는 걸 알 수 있다.
- 성능 및 분석: HTTP의 경우에는 HTTPS 프로토콜보다 오래됐기 때문에, HTTPS가 훨씬 로드 속도가 빠르며 참조 링크도 잘 추적된다.
- host
- 웹 페이지를 요청할 서버의 이름을 말하며, "dk308c.tistory.com" 같은 도메인 이름이나 IP 주소로 입력할 수 있다.
- port
- 웹 서버에서 자원을 접근하기 위해 사용하는 문이라고 볼 수 있다. 컴퓨터에서 실행되고 있는 수많은 프로세스들의 주소이기 때문에, 우리는 한 컴퓨터에서 한 개의 IP 주소로 여러 개의 connect를 가질 수 있게 한다.
- HTTP에서 사용하는 포트 번호는 80번, HTTPS의 경우에는 443번의 포트 번호가 기본으로 적용되며, 80 / 443번의 경우에는 생략이 가능하기 때문에 포트 번호를 보는 건 드물 것이다.
- path
- 서버 프로그램 내 짜인 로직이 가는 영역으로, 서버 개발자의 경우에는 각 경로에 맞춰 코드를 짠다.
- query
- 웹 서버와 통신 시 데이터를 요청할 때!!!! 가장 중요한 부분이라고 보면 된다. 우리는 쿼리 스트링을 통해 서버에게 특정 데이터를 달라고 요청할 수 있다.
- query의 경우에는 path 뒤에 ?를 기점으로 해서 key=value 형태로 데이터를 표현하게 된다.
- 또한, queryString으로 요청할 데이터를 이을 때는 &를 사용하여 정보를 요청하게 된다.
참고 자료
[네트워크] URL의 이해 - protocol, host, port, path, query
URL의 구조 protocol: 통신규약, 사용자가 서버에 접속할 때 어떤 방식으로 통신할 지 정의한다. HTTP(Hyper Text Transfer Protocol): 웹 브라우저와 웹 서버가 서로 데이터(하이퍼 텍스트)를 주고받기 위해
cotak.tistory.com
https://www.grabbing.me/URL-018cdd1bb4b541fab6246569244fcf93
URL 구조 이해하기
URL 구성 요소를 보면 순서대로 아래와 같이 나눌 수 있습니다.
www.grabbing.me
https://lxxyeon.tistory.com/85
[Web] URL 구성요소
1. 프로토콜 식별자 (protocol) 서로 다른 컴퓨터 간에 통신을 하기 위한 규약 웹 브라우저가 서버와 내용을 주고받을 때 사용할 규칙 이름. 웹 페이지의 주소를 표현할 때는 http(Hyper Text Transfer Protoc
lxxyeon.tistory.com
https://aws.amazon.com/ko/compare/the-difference-between-https-and-http/
HTTP와 HTTPS 비교 - 전송 프로토콜 간의 차이점 - AWS
1996~1997년에 출시된 최초의 HTTP 버전이 HTTP/1.1입니다. HTTP/2와 HTTP/3은 프로토콜 자체를 업그레이드한 버전입니다. 데이터 전송 시스템을 수정하면서 효율성을 개선했습니다. 예를 들어, HTTP/2는 텍
aws.amazon.com
https://mangkyu.tistory.com/98
[Web] HTTP와 HTTPS의 개념 및 차이점
1. HTTP란? [ HTTP(Hyper Text Transfer Protocol)란? ] HTTP(Hyper Text Transfer Protocol)란 서버/클라이언트 모델을 따라 데이터를 주고 받기 위한 프로토콜이다. 즉, HTTP는 인터넷에서 하이퍼텍스트를 교환하기 위
mangkyu.tistory.com
Info.plist Default Configuration 오류

콘솔창에서 친절하게 알려주는 오류를 봐서도 알 수 있지만, Info.plist 상에서 있어야 할 친구들이 없어서 나타나는 오류였다!
해당 Info.plist 창을 보면 다음과 같다.
... ... 왠지 많이 허전하지 않은가?

참고로 제대로 동작하는 다른 프로젝트의 Info.plist는 다음과 같다.

아하. 뭐가 많이 없군뇨. ^_^
없는 리스트들을 찾아서 잘 넣어주고 값을 지정해 주면 된다.

다른 프로젝트를 따라서 Info.plist를 잘 수정해주면 잘 동작한다!
아마 http 관련 설정을 할 때 잘못 건드렸던 것 같다. ^_^ ...
담부터 조심하자앙
왜 맨날 delegate 연결을 까묵을까?
실습에서 예제로 했던 프로젝트에서 UITableViewDataSourcePrefetching Protocol을 이용하여 pagenation 기능을 구현했는데, 테이블 뷰를 생성하고 prefetchRowAt에서 필요한 데이터를 다운받아서 cellForRowAt에서 리소스와 데이터들을 cell에 적용시켜주는 부분까지는 했다.
근데? 막상 빌드를 해 보면 prefetching을 하기 전과 같이 무한 스크롤이 되지 않았다. (가장 첫 화면만 나옴...)
왜 그럴까? 하고 여기저기 살펴보다가 아진짜뭐지?? 하고 강의 자료를 보니까 나와있었다.

1시간 동안 웹에 검색해 보다가 강의 자료 보고 3분만에 알앗다
나는바보엿고나.
Class 'MoreViewController' has no initializers 오류
말 그대로 변수 초기화가 제대로 되지 않아 발생하는 오류였다.
변수 선언만 하고 초기화를 하지 않아 발생하는 것 같음... ^_^

요 isEnd를 ...

초기화해 주니 해결~
Pagenation
기존에 구현한 테이블뷰에서 추가시켜 준 부분은 다음과 같다.
- tableView Extension에 UITableViewDataSourcePrefetching 추가
- ViewDidLoad에서 tableView에 prefetchDataSource 연결
- 변수 추가
- page: 각 페이지를 알려 주는 page 변수 추가
- isEnd: 이 페이지가 마지막인지 아닌지를 서버에서 받아오는 변수 추가
- queryText tableView(cancelPrefetchingForRowsAt) 함수에서 : searchBar.Text를 제대로 받아오지 못하더라. 그래서 그냥 받아올 때 queryText에 저장해 준 이후에 서버와 통신하는 함수를 호출 시 그 값을 넣어 주었다.
- searchButton을 눌렀을 때 저장되고, cancelButton을 눌렀을 때는 그 값이 같이 초기화되도록 했다.
- callRequest 함수에 매개변수 추가
- 이제는 검색어뿐만 아니라 해당 페이지 수에 맞추어 데이터를 가져와야 하므로 위에 추가한 변수를 queryString 값에 추가해 준다.
import UIKit
import Alamofire
import SwiftyJSON
import Kingfisher
struct Book {
var title: String
var author: String
var publisher: String
var price: String
var imageURL: String
var description: String {
return "\(author) · \(publisher) · \(price)"
}
}
class MoreViewController: UIViewController, UISearchBarDelegate {
let searchBar = UISearchBar()
@IBOutlet weak var searchTableView: UITableView!
var bookList: [Book] = []
var isEnd: Bool = false
var page: Int = 1
var queryText = ""
override func viewDidLoad() {
super.viewDidLoad()
searchTableView.dataSource = self
searchTableView.delegate = self
searchTableView.prefetchDataSource = self // pagenation을 위해 추가해준 거임!!
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
guard let text = searchBar.text else { return }
queryText = text
callRequest(text: text, page: page)
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
queryText = ""
bookList = []
searchTableView.reloadData()
}
func callRequest(text: String, page: Int) {
guard let text = text.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else { return }
let url = "https://dapi.kakao.com/v3/search/book?target=title&query=\(text)&size=20&page=\(page)"
print(url)
let header: HTTPHeaders = ["Authorization": "KakaoAK cf98a391517cae5208a42c51880b5107"]
AF.request(url, method: .get, headers: header).validate().responseJSON { response in
switch response.result {
case .success(let value):
let json = JSON(value)
// 필요한 데이터 저장
self.isEnd = json["meta"]["is_end"].boolValue
let items = json["documents"].arrayValue
for book in items {
let title = book["title"].stringValue
let price = book["price"].stringValue
let publisher = book["publisher"].stringValue
var authors: String {
if book["authors"].count == 1 {
return book["authors"][0].stringValue
} else {
let mainAuthor: String = book["authors"][0].stringValue
let nums = book["authors"].count - 1
return mainAuthor + "외 \(nums)명"
}
}
var imageURL: String {
if book["thumbnail"].stringValue.isEmpty {
return "noImage"
} else {
return book["thumbnail"].stringValue
}
}
self.bookList.append(Book(title: title, author: authors, publisher: publisher, price: price, imageURL: imageURL))
}
self.searchTableView.reloadData()
case .failure(let error):
print(error)
}
}
}
extension MoreViewController: UITableViewDelegate, UITableViewDataSource, UITableViewDataSourcePrefetching {
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) {
// queryText(검색어)가 비었다면 종료
guard !queryText.isEmpty else { return }
// 이 for문에서 pagenation이 구현된다.
// indexPath(각 셀의 위치)의 배열인 indexPaths를 돌면서 비교한다.
// 그 안에서 만약 indexPath가 bookList.count가 같다면 그 부분이 페이지의 끝이라는 소리니까
// 페이지가 끝나기 전에 데이터를 가져오는 조건을 설정해 준다.
// 또, 중요한 점이 json 데이터를 가져올 때 meta section에서 페이지가 끝났는지 볼 수 있는 is_end가 있다. (queryString 값은 각 json마다 다를 수 있음)
// 이 is_end를 서버에서 매번 가져오는데, 이 페이지가 끝 페이지가 아닐 때 새 페이지를 로드할 수 있으므로 이 값이 false일 때 로드하도록 한다.
// 또한, 최대 페이지 값을 설정해 주어 서버에서 제공해 주는 데이터의 페이지값을 넘는 걸 요청하여 오류가 나지 않도록 한다.
// Kakao 책 검색 API의 경우에는 size와 page 값은 최대 50까지였다.
for indexPath in indexPaths {
if bookList.count - 1 == indexPath.row && isEnd == false && page < 30 {
// 위 조건이 맞으면 새 페이지를 가져와야 하므로, 페이지 수를 증가시킨다.
page += 1
// 이후 callRequest(text:page:) 함수를 실행하여 서버에 데이터를 요청한다.
callRequest(text: queryText, page: page)
}
}
}
... ...
}
하 ... validate값에 200...400 넣고서 잘 받아왔을 때는 데이터를 띄워주고 아닐 때는 alert을 띄워주는 것도 넣고 싶은데
시간이 시간이라 오늘은 일찍 자보려고 한다...
ㅠㅠ 과제 땜에 잠을 좀 줄였떠니 그 여파가 어제부터 오늘까지 쭉...... 온 거 같다.
어제도 어?! 늦게 일어나서 오프라인에 늦게 가구...
오늘은 심지어 지각했다 ㅁㅊ거아님?? ㅠ,ㅠ
꿈에도모르고(ㄹㅇ 꿈에서도몰랏음) 자다가 그냥 통화 진동에는 깬 게 어이없다
지금 통화 내용도 기억 안 나는데 유일하게 기억나는 거라고는 연히님.. 일어나셔야죠... 저H입니다... 하셔서 네??? 햇다가
H요 ... 하셔서 아!!!!!! 하고 바로 벌떡 일어낫던 기억만 난다...
s너무감사하다............... 그리고너무죄송함.ᐟ.ᐟ.ᐟ.ᐟ.ᐟ.ᐟ.ᐟ.ᐟ.ᐟ.ᐟ.ᐟ.ᐟ
오늘을 처음이자 마지막 지각으로 하고 다음부터 부지런하게 산다.
ㄹㅇ.
'iOS' 카테고리의 다른 글
[Swift] ARC(Automatic Reference Counting) (2/2) (2) | 2023.09.02 |
---|---|
[Swift] Singleton Pattern은 왜 class로만 만들까? (0) | 2023.08.13 |
[Swift] instance / Type (0) | 2023.08.01 |
[Swift] Enum (0) | 2023.07.30 |
[UIKit] UITableViewController (0) | 2023.07.27 |