0

如何检查NSData dataWithContentsOfURL辅助线程中的解析是否完成?当每个图像完成后,我想打开我的视图控制器。不是以前。现在我可以直接打开我的视图控制器,有时如果我要快速我的表格视图没有图像,因为它们还没有完成。有任何想法吗?

以下代码发生didFinishLaunchingWithOptions在 AppDelegate 中。我使用 SBJSON 框架进行解析。

(我在这个项目中使用故事板,所以没有打开第一个视图控制器的代码)

代码:

NSString *filePath = [[NSBundle mainBundle] pathForResource:@"json_template" ofType:@"json"];
NSString *contents = [NSString stringWithContentsOfFile: filePath  encoding: NSUTF8StringEncoding error: nil];
SBJsonParser *jsonParser = [[SBJsonParser alloc] init];
NSMutableDictionary *json = [jsonParser objectWithString: contents];
tabs = [[NSMutableArray alloc] init];
jsonParser = nil;

//parsing json into model objects
for (NSString *tab in json)
{
    Tab *tabObj = [[Tab alloc] init];
    tabObj.title = tab;

    NSDictionary *categoryDict = [[json valueForKey: tabObj.title] objectAtIndex: 0];
    for (NSString *key in categoryDict)
    {

        Category *catObj = [[Category alloc] init];
        catObj.name = key;


        NSArray *items = [categoryDict objectForKey:key];

        for (NSDictionary *dict in items)
        {
            Item *item = [[Item alloc] init];
            item.title = [dict objectForKey: @"title"];
            item.desc = [dict objectForKey: @"description"];
            item.url = [dict objectForKey: @"url"];

            if([dict objectForKey: @"image"] != [NSNull null])
            {

                dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^(void)
                               {
                                   NSURL *imgUrl = [NSURL URLWithString: [dict objectForKey: @"image"]];
                                   NSData *imageData = [NSData dataWithContentsOfURL: imgUrl];

                                   dispatch_async( dispatch_get_main_queue(), ^(void)
                                   {
                                       item.image = [UIImage imageWithData: imageData];

                                   });
                               });
            }
            else
            {
                UIImage *image = [UIImage imageNamed: @"standard3.png"];
                item.image = image;
            }

            [catObj.items addObject: item];

        }

        [tabObj.categories addObject: catObj]; 
    }

    [tabs addObject: tabObj];


}

//sort array 
[tabs sortUsingComparator:^NSComparisonResult(id obj1, id obj2){


    Tab *r1 = (Tab*) obj1;
    Tab *r2 = (Tab*) obj2;

    return [r1.title caseInsensitiveCompare: r2.title];

}];



/***** END PARSING JSON *****/

[[UINavigationBar appearance] setTitleTextAttributes: @{
                    UITextAttributeTextShadowOffset: [NSValue valueWithUIOffset:UIOffsetMake(0.0f, 0.0f)],
                    UITextAttributeFont: [UIFont fontWithName:@"GreatLakesNF" size:20.0f]
 }];

UIImage *navBackgroundImage = [UIImage imageNamed:@"navbar.png"];
[[UINavigationBar appearance] setBackgroundImage:navBackgroundImage forBarMetrics:UIBarMetricsDefault];
UIImage *backButtonImage = [[UIImage imageNamed:@"backBtn.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0)];

UIImage *backButtonSelectedImage = [[UIImage imageNamed:@"backBtn_selected.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0)];
[[UIBarButtonItem appearance] setBackButtonBackgroundImage:backButtonImage forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[[UIBarButtonItem appearance] setBackButtonBackgroundImage:backButtonSelectedImage forState: UIControlStateHighlighted barMetrics:UIBarMetricsDefault];


return YES;

另外,如果这种解析方式不好,请告诉我!

4

1 回答 1

0

首先,您不应该使用这种方式从远程主机下载任何内容。有很多库,例如AFNetworkingASIHTTPRequest

它围绕 CFNetwork 或 NSURLConnection 来处理诸如重定向、错误处理等之类的事情。所以你绝对应该转向其中之一(或基于 NSURLConnection 实现你自己的)。

作为对您问题的直接回答:您应该使用某种标识符来计算下载的图像(即 for-loop 迭代计数器)并通过 +[UINotificationCenter defaultCenter] 作为某些自定义通知的参数传递。

示例(假设您通过 +[NSData dataWithContentsOfURL:] 阻塞当前线程):

for (int i = 0; i < 10; i++) {
    [[NSNotificationCenter defaultCenter] postNotificationName:@"someCustomNotificationClassName" object:nil userInfo:@{ @"counter" : @(i) }];
}

基于 NSNotification 的方法的更多扩展示例:

- (id)init {
    self = [super init];
    if (self) {
        // subscribing for notification
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleDataDownload:) name:@"someCustomNotificationClassName" object:nil];
    }

    return self;
}

- (void)dealloc {
    // unsubscribing from notification on -dealloc
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

#pragma mark - downloading delegation

- (void)handleDataDownload:(NSNotification *)notification {
    NSDictionary *userInfo = [notification userInfo];
    int counter = [userInfo[@"counter"] intValue];
    if (counter == 10) {
        // do some work afterwards
        // assuming that last item was downloaded
    }
}

您还可以使用回调技术来管理下载状态的处理:

void (^callback)(id result, int identifier) = ^(id result, int identifier) {
    if (identifier == 10) {
        // do some work afterwards
    }
};

for (int i = 0; i < 10; i++) {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, kNilOptions), ^{
        // some downloading stuff which blocks thread
        id data = nil;
        callback(data, i);
    });
}
于 2013-04-29T09:02:36.333 回答