2

我有一个基于块的枚举设置来遍历一个 NSDictionaries 数组,如下所示:

__block NSURL *contentURL;

 //This method of enumerating over the array gives the bad_access error
[documents enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {

    NSString *aName = [(NSDictionary *)obj objectForKey:@"Name"];

    if([aName isEqualToString:name]) {

        contentURL = [NSURL URLWithString:[(NSDictionary *)obj objectForKey:@"Content"]];
        *stop=YES;
    }
}];

NSLog(@"Content URL for issue with name %@ is %@", name, contentURL);

contentURL如果我使用这种方法,当我尝试在 NSLog 语句中打印出来时,会出现 EXC_BAD_ACCESS 错误。

但是,如果我像这样枚举数组:

NSURL *contentURL;

//This method of enumerating over the array works fine
for (NSDictionary *obj in documents) {

    NSString *aName = [obj objectForKey:@"Name"];

    if([aName isEqualToString:name]) {

        contentURL = [NSURL URLWithString:[obj objectForKey:@"Content"]];

    }
}

NSLog(@"Content URL for issue with name %@ is %@", name, contentURL);

一切正常。为什么是这样?

4

2 回答 2

3

不久前我遇到了类似的问题。

事实证明,一些基于块的枚举方法将枚举包装在自动释放池中。由于您正在分配一个自动释放的对象,因此它会在-enumerateObjectsUsingBlock:返回之前被释放。

(我遇到了问题-[NSDictionary enumerateKeysAndObjectsUsingBlock:,但同样的原则适用于这里)

试试这个:

contentURL = [[NSURL alloc] initWithString:[(NSDictionary *)obj objectForKey:@"Content"];

出于兴趣,您在使用ARC吗?如果你是,我希望它会添加一个-retain任务。

编辑: 您正在使用 ARC,所以这不是您问题的答案。分配给 __block 变量将保留对象(除非您在 ARC 中遇到错误,这不太可能。您提供的代码在使用 Apple LLVM 5.0 编译时没有此问题)。

您的问题很可能出在其他地方,并且从使用便捷构造函数进行更改只是掩盖了问题。

同样,在枚举期间设置的自动释放池可能会揭示代码中其他地方引起的问题。它解释了为什么切换到使用快速枚举似乎可以解决问题,但和以前一样,它可能只是掩盖了代码中其他地方引起的问题。

我将在此处留下答案,因为有关自动释放池的信息可能仍然与偶然发现此问题的人相关。

于 2013-07-22T21:37:00.800 回答
0

如果您使用 ARC,正如您所说的那样,那么您显示的代码不会产生您描述的问题。您必须在其他地方遇到问题,或者您的代码与您描述的不一样。

于 2013-07-25T04:14:48.917 回答