Alamofire는 Swift 언어를 위한 HTTP 네트워킹 라이브러리로, iOS 및 macOS 애플리케이션 개발에 사용된다. Alamofire를 사용하면 네트워크 요청을 쉽게 만들고 관리할 수 있으며, 서버와의 데이터 통신을 처리하는 데 도움이 된다.
Alamofire의 주요 특징
Alamofire Pacakage
🔗 https://github.com/Alamofire/Alamofire
Alamofire 사용법
import Alamofire
Alamofire.request("https://example.com/api/data").responseJSON { response in
if let data = response.data {
// JSON 파싱 또는 데이터 처리
}
}
import Alamofire
let parameters: Parameters = ["key": "value"]
Alamofire.request("https://example.com/api/post", method: .post, parameters: parameters).responseJSON { response in
if let data = response.data {
// JSON 파싱 또는 데이터 처리
}
}
import Alamofire
Alamofire.download("https://example.com/image.jpg").responseData { response in
if let data = response.result.value {
let image = UIImage(data: data)
// 이미지를 사용하거나 처리
}
}
API
enum API {
static let baseUrl: String = "https://youtube.googleapis.com/youtube/v3/"
static let key: String = "발급받은 API KEY"
}
API를 받아오기 전에 base URL과 지난 포스팅에서 발급받은 API KEY를 enum으로 만들어준다.
API Manager
처음에 api를 html에서 확인했을 때 아래와 같이 데이터가 호출되는 걸 볼 수 있다.
지금은 video에 대한 정보를 가져오는 Endpoint로 불러왔기 때문에 이렇게 보이는 거고, 각자 필요한 데이터를 가이드에서 확인한 후 Endpoint를 지정해주면 된다.
{
"kind": "youtube#videoListResponse",
"etag": "fsSt6aCW9h1L51_Saqof0QamBa0",
"items": [
{
"kind": "youtube#video",
"etag": "bQuiUMzicTNZIVyp0wWPOJTB8rM",
"id": "r7LzjutoXIo",
"snippet": {
"publishedAt": "2023-09-03T08:08:38Z",
"channelId": "UCN5XdqTDRbyjXPF5NXUqWdA",
"title": "파리지앵 캐릭터 만들어준 항도니랑 간만에 떠드는 무도 이야기",
"description": "형돈아 항상 널 응원하고, 고마워!\n\n00:00 하이라이트\n01:04 오프닝\n01:42 항도니 입장\n17:59 Back to the 순정마초\n\n#정형돈 #무한도전 #파리돼지앵",
"thumbnails": {
"default": {
"url": "https://i.ytimg.com/vi/r7LzjutoXIo/default.jpg",
"width": 120,
"height": 90
},
...
"standard": {
"url": "https://i.ytimg.com/vi/r7LzjutoXIo/sddefault.jpg",
"width": 640,
"height": 480
},
...
},
"channelTitle": "요정재형",
"tags": [
"정재형",
"요정재형",
"요정",
...
],
"categoryId": "22",
"liveBroadcastContent": "none",
"localized": {
"title": "파리지앵 캐릭터 만들어준 항도니랑 간만에 떠드는 무도 이야기",
"description": "형돈아 항상 널 응원하고, 고마워!\n\n00:00 하이라이트\n01:04 오프닝\n01:42 항도니 입장\n17:59 Back to the 순정마초\n\n#정형돈 #무한도전 #파리돼지앵"
},
"defaultAudioLanguage": "ko"
}
}
],
"nextPageToken": "CAUQAA",
"pageInfo": {
"totalResults": 200,
"resultsPerPage": 5
}
}
나는 이 데이터 중에 썸네일 이미지(url)와 영상 제목(title), 채널명(channelTitle) 세개를 뽑아 쓸거다.
일단 API를 관리할 수 있는 Manager 클래스를 하나 만들어준다.
import Alamofire
class APIManager {
static let shared = APIManager()
private init() {}
func fetchVideos(pageToken: String, completion: @escaping (Result<Any, AFError>) -> Void) {
let url = API.baseUrl + "videos"
let apiParam = [
"part": "snippet",
"chart": "mostPopular",
"maxResult": 500,
"regionCode": "KR",
"key": API.key,
"pageToken": "\(pageToken)"
] as [String: Any]
AF.request(url, method: .get, parameters: apiParam)
.validate()
.responseJSON { response in
completion(response.result)
debugPrint(response)
}
}
}
API Manager를 통해 읽어온 데이터를 필요한 것만 골라서 사용하려고 한다.
일단 만들어둔 CollectionViewCell에 들어갈 썸네일, 영상 제목, 채널명을 저장할 빈 배열을 만들어준다. 그리고 셀을 선택했을 때 디테일페이지에 넘겨줄 video의 고유 id도 저장할 배열을 만들었다.
// MARK: - Variables
private var nextPageToken: String?
static var videoIds: [String] = []
private var thumbnails: [UIImage] = []
private var titles: [String] = []
private var users: [String] = []
loadVideo()
홈 화면을 로드할 때 프로퍼티로 만들어둔 배열에 필요한 항목들을 append해주고, 배열에 있는 순서대로 셀에 보여줄거다.
// MARK: - YouTube Video Load
private func loadVideo(pageToken: String? = nil) {
APIManager.shared.fetchVideos(pageToken: nextPageToken ?? "") { [weak self] result in
switch result {
case .success(let data):
if let json = data as? [String:Any],
let items = json["items"] as? [[String:Any]] {
for item in items {
if let id = item["id"] as? String,
let snippet = item["snippet"] as? [String:Any],
let title = snippet["title"] as? String,
let thumbnails = snippet["thumbnails"] as? [String:Any],
let standard = thumbnails["standard"] as? [String:Any],
let thumbnailUrl = standard["url"] as? String,
let user = snippet["channelTitle"] as? String {
AF.request(thumbnailUrl).responseData { response in
switch response.result {
case .success(let data):
if let image = UIImage(data: data) {
HomeViewController.videoIds.append(id)
self?.thumbnails.append(image)
self?.titles.append(title)
self?.users.append(user)
DispatchQueue.main.async {
self?.collectionView.reloadData()
}
} else {
print("Failed to convert data to UIImage")
}
case .failure(let error):
print("Image download error: \(error)")
}
}
}
}
self?.nextPageToken = json["nextPageToken"] as? String
}
case .failure(let error):
print(error)
}
}
}
처음 데이터를 불러오면 5개밖에 안뜨는데, api url 자체에서 초기 보여주는 데이터가 5개라서 그렇다.
그래서 nextPageToken을 사용해서 다음 페이지를 로드하게 되는데, 그럼 '그 다음페이지를 로드하는 기준을 언제로 잡을까'를 고민해야 한다.
scrollViewDidScroll()
scrollViewDidScroll은 UIScrollViewDelegate 프로토콜에 정의된 메서드 중 하나로, 스크롤 뷰의 스크롤 동작이 발생할 때 호출되는 메서드이다. 이 메서드를 사용하면 스크롤 뷰의 스크롤 이벤트에 대한 응답을 구현할 수 있다.
그럼 스크롤을 내렸을 때 로드할 함수를 구현하고 해당 함수를 delegate에 추가해준다.
private func loadMoreData() {
loadVideo(pageToken: nextPageToken)
nextPageToken = ""
}
extension HomeViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let offsetY = scrollView.contentOffset.y
let contentHeight = scrollView.contentSize.height
let scrollViewHeight = scrollView.frame.size.height
if offsetY > contentHeight - scrollViewHeight {
loadMoreData()
}
}
}
근데 지금은 문제가 좀 있다..
loadVideo가 스크롤을 내릴때 여러번 호출이 되서 같은 영상이 반복해서 보이고 있다..
조금 더 문제를 파악한 다음에 조치를 취해야겠다..ㅠ
저는 아직 네트워크 활용이 어려운데 잘 활용하시는 것 같네요! 글 잘 참고하겠습니다!