【问题标题】:iOS instance variables not initialised from within a blockiOS 实例变量未从块内初始化
【发布时间】:2013-05-19 18:04:42
【问题描述】:

我正在使用 parse.com 作为我的应用程序的后端。 我需要从我的后端获取信息并使用这些信息初始化一个实例。 我使用此代码来做到这一点:

    - (id) initWithTeamId:(NSString *)teamId
{
__block NSString *str;
__block FrFTeam *blockSelf = self;
PFQuery *query = [PFQuery queryWithClassName:@"teams"];
[query getObjectInBackgroundWithId:teamId block:^(PFObject *object, NSError *error) {
    str = [object objectForKey:@"teamName"];
    (void)[blockSelf initWithName:str players:nil thumb:nil];
}];

return self;
}

当这段代码完成后,self.name 设置为 null, 我究竟做错了什么? 谢谢!

【问题讨论】:

    标签: iphone ios objective-c objective-c-blocks parse-platform


    【解决方案1】:

    试试这个代码:

    // call init on the object, then setup the team id
    - (id)initWithTeamId:(NSString *)teamId
    {
        self = [super init];
        if (self) {
            [self setupWithTeamId:teamId];
        }
    
        return self;
    }
    
    - (void) setupWithTeamId:(NSString *)teamId
    {
        __weak FrFTeam *blockSelf = self;
    
        PFQuery *query = [PFQuery queryWithClassName:@"teams"];
        [query getObjectInBackgroundWithId:teamId block:^(PFObject *object, NSError *error) {
            NSString *name = [object objectForKey:@"teamName"];
            NSLog(@"Received name: %@ from object: %@", name, object);
            [blockSelf setName:name];
        }];
    }
    

    然后,从initWithName:... 更改方法的名称,因为这不是真正的init 方法,因为您在调用setupWithTeamId: 之前已经完成了init。

    如果您需要在 init 方法返回之前完成解析位,您应该:

    1. 在对对象调用 init 之前调用 parse 以获取详细信息
    2. 使用 getObjectWithId: --- 不推荐,因为这会阻塞 init 中的线程,这是个坏主意

    【讨论】:

    • 谢谢,这还是不行,初始化后:FrFTeam *tmpTeam = [[FrFTeam alloc] init];并使用您的方法:[tmpTeam setupWithTeamId:team.objectId];名称仍然为空
    • 在调用该方法后立即为 nil(并且应该是),因为完成处理程序充其量是在当前 runloop 的 END 安排的,因此无法立即填充 name 字段没有阻止请求。我的建议 KVO,您可以听取名称的更改(如果设置正确)并根据更改采取行动。
    【解决方案2】:

    很确定原因在于您正在调用的方法名称 -getObjectInBackgroundWithId:block:(它指定 InBackground,这表明该块在稍后的某个阶段而不是立即被调用)

    这表明您最终得到 self == nil(因为您没有在方法中调用任何其他初始化程序。

    对象的初始化必须是同步的。

    【讨论】:

    • 有没有办法异步获取数据,初始化同步?
    • 仅当您在后台线程中处理 init 时,但 init 本身必须是同步的。我注意到您向初始化程序传递了很多 nil,名称字符串甚至是初始化对象所必需的吗?也许你可以初始化它然后开始加载(异步),填充名称字段?这就是给出的代码中其他答案的作用。
    • "这表明你最终得到 self == nil" 不。如果你查看 OP 的代码,initWithTeamId: 方法返回的是self,即它的对象被调用。不是nil。
    • 好的,是的,你有这个权利,self 会被退回。但是, blockSelf 是在块中初始化的那个,并且从未使用过该初始化的返回值,所以我想说最终目标仍然没有实现,在这种情况下 self 也可以 == nil (除了内存已分配给对象)。我想我想说的是 self != 一个完全初始化的 self,它只是一个外壳,并没有按照 NSObjects 文档准备好使用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-14
    • 2013-07-04
    • 1970-01-01
    • 1970-01-01
    • 2017-04-05
    • 2011-03-18
    • 2010-11-26
    相关资源
    最近更新 更多