The following Objective-C Code processes the NSURLSession code (via viewDidLoad()) before the UICollectionView's delegate (which is what I want):
--- Session ---
--- Session ---
--- {CellForItemAtIndexPath} ---
--- {CellForItemAtIndexPath} ---
--- {CellForItemAtIndexPath} ---
--- {CellForItemAtIndexPath} ---
--- {CellForItemAtIndexPath} ---
--- {CellForItemAtIndexPath} ---
--- {CellForItemAtIndexPath} ---
--- {CellForItemAtIndexPath} ---
--- {CellForItemAtIndexPath} ---
--- {CellForItemAtIndexPath} ---
--- {CellForItemAtIndexPath} ---
--- {CellForItemAtIndexPath} ---
--- {CellForItemAtIndexPath} ---
--- {CellForItemAtIndexPath} ---
--- {CellForItemAtIndexPath} ---
Note: the above debug msgs were made within their respective break properties.
The abridged Objective-C code:
@interface MainViewController () <UICollectionViewDataSource, UICollectionViewDelegate>
@property (weak, nonatomic) IBOutlet UICollectionView *collectionView;
@property (nonatomic, strong) NSMutableArray *downloaders;
@property (nonatomic, strong) NSArray *photoInfos;
@end
@implementation MainViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self fetchFlickrPhotoWithSearchString:@"Ric"];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if (_currentImageDownloader) {
[_downloaders replaceObjectAtIndex:_selectedItemIndex withObject:_currentImageDownloader];
}
}
// -----------------------------------------------------------------------------------------------------------------------
#pragma mark -
- (void)fetchFlickrPhotoWithSearchString:(NSString *)searchString {
SimpleFlickrAPI *flickr = [SimpleFlickrAPI new];
[[[NSURLSession sharedSession] dataTaskWithURL:[flickr getURLForString:@"Ric"]
completionHandler:^(NSData *data,
NSURLResponse *response,
NSError *error) {
if (!error) {
NSString *string = [flickr stringByRemovingFlickrJavaScript:data];
NSData *jsonData = [string dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:jsonData
options:NSJSONReadingAllowFragments
error:&error];
self.photoInfos = [[jsonDict objectForKey:@"photos"] objectForKey:@"photo"];
NSMutableArray *downloaders = [[NSMutableArray alloc] initWithCapacity:[_photoInfos count]];
for (NSInteger index = 0; index < [_photoInfos count]; index++) {
ImageDownloader *downloader = [[ImageDownloader alloc] initWithDict:_photoInfos[index]];
[downloaders addObject:downloader];
}
self.downloaders = downloaders; // ...link local array with instance array 'downloaders' (Note: same object!).
dispatch_async(dispatch_get_main_queue(), ^{
[self.collectionView reloadData];
});
} else {
NSLog(@"*** {SessionDataError}: %@",error);
// ...Handle Error.
}
}] resume];
}
// -----------------------------------------------------------------------------------------------------------------------
#pragma mark - UICollectionViewDelegate methods
// ...to be implemented later.
// -----------------------------------------------------------------------------------------------------------------------
#pragma mark - UICollectionViewDataSource methods
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return [self.photoInfos count];
}
// -----------------------------------------------------------------------------------------------------------------------
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"PhotoCell" forIndexPath:indexPath];
...
...
return cell;
}
...
@end
However... Swift's processing pattern is different. The UIControllerView's data-source delegate methods are process PRIOR to the NSURLSession:
--- {UICollectionView numberOfItems...} ---
--- {cellForItemAtIndexPath} ---
--- {cellForItemAtIndexPath} ---
--- {cellForItemAtIndexPath} ---
--- {cellForItemAtIndexPath} ---
--- {cellForItemAtIndexPath} ---
--- {session} ---
--- {session} ---
Here's the Swift 'equivalent' code:
import UIKit
var gPhotoData:Array<Dictionary<String,AnyObject>>?
var gDownloaders:NSMutableArray = NSMutableArray()
var currentImageDownloader:ImageDownloader?
var gSelectedItemIndex:Int?
class ViewController: UIViewController {
@IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
fetchFlickrPhotoWithSearchString("Ric");
}
// -----------------------------------------------------------------------------------------------------
// MARK: -
func fetchFlickrPhotoWithSearchString(searchString:String) {
let url = getURLForString("Ric")
let task = NSURLSession.sharedSession().dataTaskWithURL(url) {(data, response, error) in
if let httpRes = response as? NSHTTPURLResponse {
if httpRes.statusCode == 200 {
let string = stringByRemovingFlickrJavaScriptFromData(data)
let data = string.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)
let JSON: AnyObject? = NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments, error: nil)
let rawDataDict = JSON as Dictionary<String,AnyObject>!
let photos: AnyObject? = rawDataDict["photos"]
gPhotoData = (photos!["photo"] as Array<Dictionary<String,AnyObject>>)
let myCount = (gPhotoData!.count - 1)
for index in 0...myCount {
let smirf = gPhotoData![index]
let downloader:ImageDownloader = ImageDownloader(dict: smirf)
gDownloaders.addObject(downloader)
}
dispatch_async(dispatch_get_main_queue(), {
// ...do something.
})
}
}
}
task.resume()
} // ...end class ViewController().
// =======================================================================================================================
// MARK: - Action Methods
@IBAction func exitAction(sender: AnyObject) {
exit(0)
}
}
// =======================================================================================================================
extension ViewController: UICollectionViewDataSource {
// -----------------------------------------------------------------------------------------------------
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if let anyData = gPhotoData {
return gPhotoData!.count
}
return 5 //...arbitrary number to avoid crashing.
}
// -----------------------------------------------------------------------------------------------------
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell: AnyObject = collectionView.dequeueReusableCellWithReuseIdentifier("photoCell", forIndexPath:indexPath)
let photoImageView = cell.viewWithTag!(1) as UIImageView
...
...
return cell as UICollectionViewCell
}
}
Note: the above debug msgs were made within their respective break properties.
Question: How do I fire-off the NSURLSession/Swift, with completion BEFORE having the UIViewController's delegate methods fire (as is done in the Objective-C version)?