For 루프의 NSURLSession을 사용하여 이미지 데이터를 다운로드 한 다음 NSMutableArray에 추가

브랜든 A

내 응용 프로그램에는 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 코드를 호출하려면 어떻게해야 합니까?

Rob

일련의 비동기 작업이 완료 될 때까지 기다리려면을 만들고 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()
    }
}

이미지 배열의 업데이트를 동기화해야합니다 (변경 가능한 배열은 스레드로부터 안전하지 않습니다).

-

질문에 대한 답을 얻었으므로 나는 아마도 두 가지 더 중요한 변화를 조언하겠다고 고백해야한다.

  1. 이미지를 배열에 보관해서는 안됩니다 (너무 많으면 메모리가 부족할 수 있기 때문입니다). JPEG 또는 PNG 파일은 너무 크지 않을 수 있지만 이미지가 RAM에서 압축되지 않은 경우 많은 메모리를 차지하고 쉽게 메모리 경고를받을 수 있습니다.

    이미지를 메모리가 아닌 영구 저장소에 다운로드하는 것을 고려할 수 있습니다. 이미지를 메모리에 저장하려면 NSCache성능상의 이유로를 사용하십시오 (하지만 메모리 경고시 제거하십시오).

    이미지가 너무 많지 않거나 모두 작다면 중요하지 않을 수 있습니다. 그러나 확장 가능한 솔루션을 찾고 있다면 앱이 모든 이미지를 배열에 보관할 필요가 없습니다.

  2. 컬렉션 뷰를 다시로드하기 전에 모든 이미지를 기다리지 않을 수 있습니다. 일반적으로 사람들은 지연 로딩을 권장합니다. 따라서 1000 개의 이미지가 있고 한 번에 20 개만 표시되는 경우 왜 1000 개의 이미지를 기다릴까요? 보이는 셀의 이미지를로드하는 데 중점을 둡니다. 또한 이미지가 다운로드 될 때 컬렉션보기에 표시되는 것을 볼 수 있습니다 (따라서 처음 20 개의 보이는 이미지가 다운로드 될 때까지 기다리지 않고 들어오는대로 표시).

    일반적으로 cellForItemAtIndexPath이미지 다운로드를 비동기 적으로 시작하고 완료되면 셀을 업데이트하여이를 수행합니다.

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

Related 관련 기사

뜨겁다태그

보관