How to run multiple NSURLSessionDownloadTask's so I can download multiple user photo streams from Instagram?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | // // 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会话,该会话从用户" 7522782"下载instagram信息。我解析数据并计算" currentResponse "数组以获取集合视图中所需的单元格数。然后,我将信息转换网址解析为UIimages并将其放入单元格中。
如何为一个以上的用户执行此操作。我想显示20位用户的照片。
请记住,我需要汇总所有用户的照片总数,以告诉我的收藏夹视图可以制作多少个单元格。
谢谢。
这是我现在想的一种方式...
首先修复您使用分派的方式...关于分派队列的好答案
1 2 | //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进行后台线程处理,然后在要运行将在后台闭包(块)内更新UI的代码时调用dispatch_get_main_queue。
1 2 3 4 5 6 7 8 9 10 | //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. } } |
现在根据您的具体情况。您正在正确地处理该用户,获取该用户的"照片"的所有网址,因此现在添加类似这样的内容以处理同一屏幕上的多个用户。问题是下载20张用户照片需要花费很长时间,但是由于您执行的是异步操作,因此屏幕不会卡住。
对照片进行矩阵处理;主阵列中的每个阵列都是每个用户的照片集。
1 | var photoUserMatrix = [NSMutableArray]() //using Swift array and NSMutableArray |
或者使用它,因为您更倾向于NSMutableArrays
1 2 | var photoUserMatrix = NSMutableArray() photoUserMatrix.addObject(NSMutableArray())//Each Photo Set per user is a new array. |
矩阵的问题是发现执行时间为O(N ^ 2)。
现在无论如何您都可以拥有X个用户,并且您的代码可以处理它。通过使用这段代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | //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的代码。
1 2 3 4 5 6 7 8 9 10 11 | 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:如果您遇到任何问题,请告诉我,我们将很乐意为您提供帮助。