내 응용 프로그램에는 UICollectionView 하위 뷰 (재사용되지 않음)가 포함 된 셀이있는 UITableView가 있습니다. collectionView의 셀에는 그림을 담기위한 단일 UIImageView가 있습니다. 모든 이미지를 한 번에 다운로드하고 배열에 저장 한 다음 이미지가 모두 다운로드되면 collectionView 셀에 배열의 내용을 표시하려고합니다 . ObjC에서 나는 이것을 여러 번 사용 NSURLConnection
했지만 Swift를 사용하고 NSURLConnection
이것을 달성 하려고 노력하고 있지만 동시성 또는 의미론 문제 일 수 있다고 생각하는 문제에 직면하고 있습니다. 내가 이것에 너무 많은 시간을 보내고 있다고 느끼기 때문에 여러분 중 한 명이 올바른 방향으로 나를 가리킬 수 있습니다.
내가 호출하는 collectionView를 포함하는 내 UITableView의 셀 하위 클래스에서
func downloadPhotosWithURLs(urls: [String]) {
var imagesMutableArray = NSMutableArray()
for url in urls {
NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: url)!, completionHandler: { (data, repsonse, err) -> Void in
if let imgData = data {
if let image = UIImage(data: imgData) {
imagesMutableArray.addObject(image)
}
else {
// PUT IN "Photo Unavailable" Pic
}
}
else {
// PUT IN "Photo Unavailable" Pic
}
}).resume()
}
// UPDATE (but async op not done)
if let downloadedImages: [UIImage] = imagesMutableArray as NSArray as? [UIImage] {
self.images = downloadedImages
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.collectionView.reloadData()
})
}
}
문제는 collectionView를 다시로드하도록 호출 할 때까지 이미지를 가져 오지 않았다는 것입니다. for 루프의 비동기 작업은 확실히 책임이 있습니다. 이미지를 모두 다운로드 한 후// UPDATE
코드를 호출하려면 어떻게해야 합니까?
일련의 비동기 작업이 완료 될 때까지 기다리려면을 만들고 dispatch_group_t
각 요청을 시작하기 전에 그룹을 입력 한 다음 완료 블록에 그룹을 남겨두고 dispatch_group_notify
각 "입력"이 일치 할 때 호출되도록 신뢰할 수 있습니다. "휴가"
func downloadPhotosWithURLs(urls: [String]) {
var images = [UIImage]()
let group = dispatch_group_create()
for url in urls {
dispatch_group_enter(group)
NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: url)!, completionHandler: { data, response, error in
if let imgData = data {
if let image = UIImage(data: imgData) {
dispatch_sync(dispatch_get_main_queue()) {
images.append(image)
}
} else {
// PUT IN "Photo Unavailable" Pic
}
} else {
// PUT IN "Photo Unavailable" Pic
}
dispatch_group_leave(group)
}).resume()
}
// UPDATE
dispatch_group_notify(group, dispatch_get_main_queue()) {
self.images = images
self.collectionView.reloadData()
}
}
이미지 배열의 업데이트를 동기화해야합니다 (변경 가능한 배열은 스레드로부터 안전하지 않습니다).
-
질문에 대한 답을 얻었으므로 나는 아마도 두 가지 더 중요한 변화를 조언하겠다고 고백해야한다.
이미지를 배열에 보관해서는 안됩니다 (너무 많으면 메모리가 부족할 수 있기 때문입니다). JPEG 또는 PNG 파일은 너무 크지 않을 수 있지만 이미지가 RAM에서 압축되지 않은 경우 많은 메모리를 차지하고 쉽게 메모리 경고를받을 수 있습니다.
이미지를 메모리가 아닌 영구 저장소에 다운로드하는 것을 고려할 수 있습니다. 이미지를 메모리에 저장하려면 NSCache
성능상의 이유로를 사용하십시오 (하지만 메모리 경고시 제거하십시오).
이미지가 너무 많지 않거나 모두 작다면 중요하지 않을 수 있습니다. 그러나 확장 가능한 솔루션을 찾고 있다면 앱이 모든 이미지를 배열에 보관할 필요가 없습니다.
컬렉션 뷰를 다시로드하기 전에 모든 이미지를 기다리지 않을 수 있습니다. 일반적으로 사람들은 지연 로딩을 권장합니다. 따라서 1000 개의 이미지가 있고 한 번에 20 개만 표시되는 경우 왜 1000 개의 이미지를 기다릴까요? 보이는 셀의 이미지를로드하는 데 중점을 둡니다. 또한 이미지가 다운로드 될 때 컬렉션보기에 표시되는 것을 볼 수 있습니다 (따라서 처음 20 개의 보이는 이미지가 다운로드 될 때까지 기다리지 않고 들어오는대로 표시).
일반적으로 cellForItemAtIndexPath
이미지 다운로드를 비동기 적으로 시작하고 완료되면 셀을 업데이트하여이를 수행합니다.
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다