1

我开始学习 iOS 开发的 Objective-C,遇到了一个让我发疯的问题。

我想要的只是做一个请求,检索 e JSON,然后将此 JSON 设置为实例属性。

-(NSArray *) retrieveAtEndpoint:(NSString *)endpointURL withRootNode:(NSString *)rootNode
{
    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat: endpointURL, fuegoWSURL]];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];

    AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
        NSDictionary *dict = (NSDictionary *) JSON;
        [self setJSONObjectsCollection: [dict objectForKey:rootNode]];

    } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
        NSLog(@"Communication Error: %@", error);
    }];

    [operation start];

    return _JSONObjectsCollection;
}

-(void) setJSONOBjectsCollectionAttribute: (NSArray *) arrayWithCollection
{
    NSLog(@"Outside Method %@", arrayWithCollection);
    self.JSONObjectsCollection = arrayWithCollection;
}

但是,我的 self.JSONObjectsCollection 属性在块内是可以的,但在外面总是空的。

你们能帮帮我吗?

4

1 回答 1

4

这是因为设置是JSONObjectsCollection异步发生的。因此,您的方法JSONObjectsCollection在设置之前返回。


因此,它可能看起来像:

- (void)retrieveAtEndpoint:(NSString *)endpointURL withRootNode:(NSString *)rootNode
{
    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat: endpointURL, fuegoWSURL]];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];

    AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
        NSDictionary *dict = (NSDictionary *) JSON;
        [self setJSONObjectsCollection: [dict objectForKey:rootNode]];

        // do here whatever you want to do now that you have your array, e.g.
        //
        // [self.tableView reloadData]; 

    } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
        NSLog(@"Communication Error: %@", error);
    }];

    [operation start];
}

请注意,retrieveAtEndpoint现在有一个void返回类型,但在完成块中,我将调用您想要在更新 JSON 对象集合后执行的任何代码。


如果这是模型对象中的一个方法,但您想提供一个接口,视图控制器可以通过该接口提供一个在成功检索 JSON 时应执行的代码块,请使用完成块:

- (void)retrieveAtEndpoint:(NSString *)endpointURL withRootNode:(NSString *)rootNode completion:(void (^)(NSError *error))completion
{
    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat: endpointURL, fuegoWSURL]];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];

    AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
        NSDictionary *dict = (NSDictionary *) JSON;
        [self setJSONObjectsCollection: [dict objectForKey:rootNode]];

        if (completion)
        {
            completion(nil);
        }

    } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
        if (completion)
        {
            completion(error);
        }
    }];

    [operation start];
}

或者,如果您想简化块参数的使用,您可以在模型对象的 .h 文件的开头(@interface块之前)定义完成块的类型:

typedef void (^RetrievalCompleteBlock)(NSError *);

然后将方法简化一点:

- (void)retrieveAtEndpoint:(NSString *)endpointURL withRootNode:(NSString *)rootNode completion:(RetrievalCompleteBlock)completion
{
    // the code here is like it is above
}

无论如何,无论您是否使用typedef,视图控制器都可以执行以下操作:

ModelObject *object = ...
NSString *rootNode = ...
[object retrieveAtEndpoint:url withRootNode:rootNode completion:^(NSError *error) {
    if (error)
    {
        // handle the error any way you want, such as

        NSLog(@"%s: retrieveAtEndPoint error: %@", __FUNCTION__, error);
    }
    else
    {
        // do whatever you want upon successful retrieval of the JSON here
    }
}];

此处的详细信息将根据您的视图控制器访问模型对象的方式、知道根节点应该是等等而有所不同。我经常会在我的完成块中包含另一个参数,即正在检索的数据,但是假设您更新了您的模型对象并可以通过这种方式访问​​它,也许这不是必需的。我只是没有足够的关于你的实现的细节来知道这里有什么,所以我让我的实现尽可能地简约。

但希望这能说明这个想法。给你的retrieveAtEndpoint方法一个完成块参数,它让视图控制器指定它在与服务器通信完成(或失败)时想要做什么。

于 2013-06-25T20:21:33.717 回答