ios - 如何运行多个 NSURLSessionDownloadTask,以便我可以从 Instagram 下载多个用户照片流?

标签 ios swift uiimage nsurlrequest nsurlsession

//
//  ViewController.swift
//  Fashun
//
//  Created by Alex Macleod on 20/10/14.
//  Copyright (c) 2014 Alex Macleod. All rights reserved.
//

import UIKit

class ViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {

var collectionView: UICollectionView?

var instanceOfCustomObject: CustomObject = CustomObject()
var accessToken: NSString!
var userDefaults: NSUserDefaults!
let colorWheel = ColorWheel()
var photoCount: Int! = 0
let photos = NSMutableArray()

override func viewDidLoad() {
    super.viewDidLoad()

    userDefaults = NSUserDefaults.standardUserDefaults()
    self.accessToken = userDefaults!.objectForKey("accessToken") as NSString
    println(self.accessToken)

//        instanceOfCustomObject.someProperty = "Hello World"
//        var accessToken : NSString? = NSString(instanceOfCustomObject.accessToken)
//        println(accessToken)
//        instanceOfCustomObject.authorize()

// Do any additional setup after loading the view, typically from a nib.
    let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
//        layout.sectionInset = UIEdgeInsets(top: 20, left: 0, bottom: 0, right: 0)
    layout.itemSize = CGSize(width: 124, height: 124)
    layout.minimumInteritemSpacing = 1.0
    layout.minimumLineSpacing = 1.0
    collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
    collectionView!.dataSource = self
    collectionView!.delegate = self
    collectionView!.registerClass(Cell.self, forCellWithReuseIdentifier: "Cell")
    collectionView!.backgroundColor = UIColor.whiteColor()
    self.view.addSubview(collectionView!)

    getData()
}

    func getData() -> Void {
        let baseUrl = NSURL(string:"https://api.instagram.com/v1/users/7522782/media/recent/?access_token=\(self.accessToken)")

//        let forcastUrl = NSURL(string: "37.8267,-122.423", relativeToURL: baseUrl)

        //        let data = NSData(contentsOfURL: forcastUrl)
        //        println(data)
        let sharedSession = NSURLSession.sharedSession()
        let downloadTask: NSURLSessionDownloadTask = sharedSession.downloadTaskWithURL(baseUrl!, completionHandler: { (location: NSURL!, response: NSURLResponse!, error: NSError!) -> Void in


            //            var urlContents = NSString.stringWithContentsOfURL(location, encoding: NSUTF8StringEncoding, error: nil)
            //            println(urlContents)

            let dataObject = NSData(contentsOfURL: baseUrl!)

            if (error == nil) {
                let responseDictionary: NSDictionary = NSJSONSerialization.JSONObjectWithData(dataObject!, options: nil, error: nil) as NSDictionary
//                println(responseDictionary)

                var currentResponse = responseDictionary.valueForKeyPath("data.images.standard_resolution.url") as NSArray



                dispatch_async(dispatch_get_main_queue(), { () -> Void in

//                    for url in currentResponse {
//                        var urlStrings: NSString = url as NSString
//                        
//                        var images =  UIImage(data: NSData(contentsOfURL: NSURL(string:urlStrings)!)!)
//
//                    }
                    for url in currentResponse {
                        var urls: NSString = url as NSString
                        //                        println(images)
                        var photoUrls = NSURL(string: urls)

                        var err: NSError?
                        var imageData :NSData = NSData(contentsOfURL: photoUrls!,options: NSDataReadingOptions.DataReadingMappedIfSafe, error: &err)!
                        self.photos.addObject(UIImage(data:imageData)!)
                        println(self.photos)
                    }

                    self.photoCount = currentResponse.count as Int

                    self.collectionView?.reloadData()

                })

            } else {

                let networkIssueController = UIAlertController(title: "Error", message: "Something went wrong get a better phone you pleb!", preferredStyle: .ActionSheet)
                let okButton = UIAlertAction(title: "OK", style: .Default, handler: nil)
                networkIssueController.addAction(okButton)
                let cancelButton = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)
                networkIssueController.addAction(cancelButton)

                self.presentViewController(networkIssueController, animated: true, completion: nil)

                dispatch_async(dispatch_get_main_queue(), { () -> Void in
                    //Stop refresh animation


                })
            }
        })

        downloadTask.resume()

    }


override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return photoCount

}

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as Cell
//                println(photos)
//            cell.textLabel.text = "Text"
    cell.imageView.image = photos.objectAtIndex(indexPath.row) as? UIImage
//    cell.photo = self.photos[indexPath.row] as? NSDictionary
    cell.imageView.backgroundColor = colorWheel.randomColor()

    return cell
}
}

如您所见,我有一个 NSURLDownload session ,它从用户“7522782”下载 Instagram 上的信息。我解析数据并对“currentResponse”数组进行计数,以获取 Collection View 中所需的单元格数。然后我解析信息将 url 转换为 UIimages 并将它们放入单元格中。

如何为超过一个用户执行此操作。我想显示 20 多个用户的照片。
请记住,我需要总结所有用户的照片总数,以告诉我的收藏 View 要制作多少个单元格。

提前致谢。

最佳答案

这是我现在想到的一种方式......

首先修复您使用调度的方式... A Good Answer about Dispatch Queues

//Might run into an issue that if you insert more heavy logic here your UI will get stuck until processing ends.
dispatch_async(dispatch_get_main_queue(), { () -> Void in }

因此,请使用 dispatch_get_global_queue 代替后台线程,然后在您想要运行将在后台闭包( block )内更新 UI 的代码时调用 dispatch_get_main_queue。

//Correct way to use it to do Background work.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), {

   //async code the callings to the NSUrlSession any other logic

       dispatch_async(dispatch_get_main_queue(), { () -> Void in 
          //Do UI Updates Code.
       }

} 

现在针对您的具体情况。您正在正确处理用户获取该用户照片的所有 url,因此现在添加类似这样的内容来处理同一屏幕的多个用户。问题是下载 20 多张用户照片需要很长时间,但由于您是异步执行的,因此屏幕不会卡住。

对照片做一个矩阵,一个数组的数组;主数组中的每个数组都是每个用户的一组照片。

var photoUserMatrix = [NSMutableArray]() //using Swift array and NSMutableArray

或者使用这个因为你更倾向于 NSMutableArrays

var photoUserMatrix = NSMutableArray()   
photoUserMatrix.addObject(NSMutableArray())//Each Photo Set per user is a new array.

矩阵的问题是在执行时间内找到东西是 O(N^2)。

无论如何,现在您可以拥有 X 数量的用户,并且您的代码会处理它。通过使用这段代码。

//Use this pseudo code to start downloading the multiple pictures for the users. 
for i in 0...countOfUsers{

   //Create the array of Photos for this user. 
   var newPhotoSet = NSMutableArray()

   //Now use your code that downloads the photos with 
   //the Urls given for that users photos. with another loop on the Count of Urls/Photos
   for pos in 0...countOfUrls{

         //Download the Image with NSUrlSession

         //and add the photo to the new Array in the CompletionHandler
         newPhotoSet.AddObject(newImageDownloaded);
   }

   photoUserMatrix.addObject(newPhotoSet)


}

显示 CollectionViewCells 的代码。

for photoSet in photoUserMatrix as (NSMutableArray) {

    var count:Int = photoSet.count
    for i in 0...count{
        //use algorithm to display downloaded pictures in CollectionView. 
        //If any image is nil do not display that image. 
       //Same Code can be used to do the sum of all photos in each array. 
    }


}

请记住,这不是最佳解决方案。此外,应用程序的设计也无济于事,在同一屏幕上为 20 多个用户加载图像是一个问题,除非图像真的非常小,否则您将在那里运行。

此外,我建议您将此工作逻辑代码添加到一个方法中,该方法将为每个需要下载图像的用户调用 Dispatch_get_global_queue,从而提高并发性。

PS:如果您遇到任何问题,请告诉我,我很乐意提供帮助。

关于ios - 如何运行多个 NSURLSessionDownloadTask,以便我可以从 Instagram 下载多个用户照片流?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26910194/

相关文章:

ios - 无法通过 TestFlight : Registered maximum number of devices 安装应用

ios - 我如何重命名swift包

ios - 存储 UIImage 的文件名或对象以在 Obj-C 中进行处理

ios - 将 UIImage 导出为 stretchableImage 导出带有在 Image 上绘制的水平线和垂直线的图像

ios - 在 Master-Detail 应用程序中为 Master/Detail View Controller 重用 UIViewController(带有 UITableView)?

iphone - 点击状态栏时滚动到顶部

ios - 从 iPhone 通过的 Stripe 卡身份验证在服务器上失败

ios - 无法将 tableView 或 collectionView 中选定的图像中的 imageView 提供给详细 View

ios - 在 swift 3 中预览操作项

iOS UIImage 剪辑到路径