如何在UICollectionView委托方法之前完成NSURLSession的完成?

时间:2014-10-06 19:55:50

标签: objective-c swift callback nsurlsession

以下Objective-C代码在 UICollectionView的委托(这就是我想要的)之前处理NSURLSession代码(通过viewDidLoad())

--- Session ---
--- Session ---
--- {CellForItemAtIndexPath} ---
--- {CellForItemAtIndexPath} ---
--- {CellForItemAtIndexPath} ---
--- {CellForItemAtIndexPath} ---
--- {CellForItemAtIndexPath} ---
--- {CellForItemAtIndexPath} ---
--- {CellForItemAtIndexPath} ---
--- {CellForItemAtIndexPath} ---
--- {CellForItemAtIndexPath} ---
--- {CellForItemAtIndexPath} ---
--- {CellForItemAtIndexPath} ---
--- {CellForItemAtIndexPath} ---
--- {CellForItemAtIndexPath} ---
--- {CellForItemAtIndexPath} ---
--- {CellForItemAtIndexPath} ---

注意:上面的调试消息是在各自的break属性中进行的。

删节 Objective-C代码:

@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

<小时/> 但是......斯威夫特的处理模式不同。 UIControllerView的数据源委托方法是NSURLSession的先行过程:

--- {UICollectionView numberOfItems...} ---
--- {cellForItemAtIndexPath} ---
--- {cellForItemAtIndexPath} ---
--- {cellForItemAtIndexPath} ---
--- {cellForItemAtIndexPath} ---
--- {cellForItemAtIndexPath} ---
--- {session} ---
--- {session} ---

这是Swift'等效'代码:

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


    }

}

注意:上面的调试消息是在各自的break属性中进行的。

问题:如何在启动UIViewController的委托方法之前完成NSURLSession / Swift的启动(如在Objective-C版本中那样)?

1 个答案:

答案 0 :(得分:0)

如果你的目标是在通过会话检索后在collectionView中显示数据,为什么不在你的dispatch_main_queue中调用collectionView.reloadData()

为了避免numberOfRows中的崩溃,请不要强制取消数组,但要对可选项return anyData.count执行操作。只有当anyData不是nil并且在可选的un-wrapping之后返回0应该没问题时,它才会调用此代码。