//
// 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
}
}
As you can see I have a NSURLDownload session that downloads info off instagram from user "7522782". I parse the data and count the "currentResponse" array to get the number of cells I need in my collection view. Then I parse the info convert urls to UIimages and put them in the cells.
How do I do this for more then one user. I want to show photos from 20+ users.
bear in mind that i'll need to sum up the total number photos from all users to tell my collection view how many cells to make.
Thanks in advance.
This is one way I thought right now...
first of all fix the way you are using dispatch... 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 }
So use dispatch_get_global_queue instead for background threading and then Call dispatch_get_main_queue when you want to run code that will update your UI inside the Background closure(Block).
//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.
}
}
Now for your specific situation. You are correctly handling the user getting all the urls for the Photos for that user, so now add something like this to handle multiple users for the same screen. Problem it is going to take a long time to download 20+ users photos, but since you are doing it async the screen wont get stuck.
Do a Matrix, an Array of arrays, of the photos; each array inside the main array is the set of photos per User.
var photoUserMatrix = [NSMutableArray]() //using Swift array and NSMutableArray
Or use this since you are more inclined to NSMutableArrays
var photoUserMatrix = NSMutableArray()
photoUserMatrix.addObject(NSMutableArray())//Each Photo Set per user is a new array.
Problem with the Matrix is that finding something is O(N^2) in execution Time.
Anyways now you can have X number of Users and your code will handle it. by using this piece of code.
//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)
}
Code to display 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.
}
}
Keep in mind that this is not the most optimal solution. Also the design of the application doesn't help, doing a load Images for 20+ users in the same screen is kind of an issue you will run there unless the images are really really small.
Also I would suggest you add this working logic code into a method, that will call the Dispatch_get_global_queue for each User that requires to download images, making it more concurrent.
PS: if you hit any issues tell me I will gladly help.