将对象分配给块外的变量 [英] Assigning objects to variable outside a block
问题描述
由于最后一个块退出时sentence
的内容消失,因此以下代码崩溃.
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// simple block test - just iterate over some items and
// add them to a string
NSArray *items = [NSArray arrayWithObjects:@"why ", @"must ", @"this ",nil];
__block NSString *sentence = @"";
[items enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop)
{
sentence = [sentence stringByAppendingFormat:@"%@",obj];
}];
// crash!
NSLog(@"Sentence is %@",sentence);
[pool drain];
return 0;
}
完成这项工作的正确/惯用方式是什么?
好吧,我离开了Xcode,玩了一会儿,这是一个正在发生的事情的模型,似乎与我所看到的相符. /p>
我在上面使用的块没有做任何特殊的事情,但是enumerateObjectsUsingBlock
代码似乎有自己的NSAutoreleasePool
,因此这似乎是导致dealloc
在对象alloc'ed
上被调用的原因,但会在区块内自动释放.
以下代码与我在上面看到的行为相匹配:
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// simple block test - just iterate over some items and
// add them to a string
typedef void (^AccArrayBlock)(id obj, int idx, BOOL *stop);
// items to 'process'
NSArray *items = [NSArray arrayWithObjects:@"why ", @"must ", @"this ",nil];
int idx = 0;
BOOL doStop = NO;
// make sentence mutable, so we can assign it inside block
__block NSString *sentence = @"";
// make a similar block to what we'd pass to enumerate...
AccArrayBlock myBlock = ^(id obj, int idx, BOOL *stop)
{
// returns and assigns an autoreleased string object
sentence = [sentence stringByAppendingFormat:@"(%d) %@ ",idx,obj];
};
// enumerate items and call block
for (NSString *item in items) {
// create a pool to clean up any autoreleased objects in loop
// remove this line, and the sentence will be valid after loop
NSAutoreleasePool *innerPool = [[NSAutoreleasePool alloc] init];
myBlock(item, idx++, &doStop);
// drain the pool, autorelease objects from block
[innerPool drain];
if (doStop) {
break;
}
}
// faults if we drained the pool
// Program received signal: EXC_BAD_ACCESS.
NSLog(@"Sentence is %@",sentence);
[pool drain];
return 0;
}
如果我删除了innerPool
对象,那么代码将按我原来的预期工作,并且NSRunLoop
池最终将清理各种NSString
对象.
注意:该线程现在是'enumerateObjectsUsingBlock autorelease'的第二个Google结果:
What is the correct / idiomatic way to make this work? Ok, I went away and played with Xcode for a bit, and here's a model of what's going on, that seems to match what I'm seeing. The block I used above isn't doing anything special, but the The following code matches in behavior what I'm seeing above: If I remove the NOTE: This thread is now the number 2 Google result for 'enumerateObjectsUsingBlock autorelease': Google 'enumerateObjectsUsingBlock+autorelease' The first result confirms this answer. Thanks all. 这篇关于将对象分配给块外的变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!enumerateObjectsUsingBlock
code appears to have its own NSAutoreleasePool
, so that seems to be what was causing dealloc
to be called on objects alloc'ed
, but autoreleased inside the block.#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// simple block test - just iterate over some items and
// add them to a string
typedef void (^AccArrayBlock)(id obj, int idx, BOOL *stop);
// items to 'process'
NSArray *items = [NSArray arrayWithObjects:@"why ", @"must ", @"this ",nil];
int idx = 0;
BOOL doStop = NO;
// make sentence mutable, so we can assign it inside block
__block NSString *sentence = @"";
// make a similar block to what we'd pass to enumerate...
AccArrayBlock myBlock = ^(id obj, int idx, BOOL *stop)
{
// returns and assigns an autoreleased string object
sentence = [sentence stringByAppendingFormat:@"(%d) %@ ",idx,obj];
};
// enumerate items and call block
for (NSString *item in items) {
// create a pool to clean up any autoreleased objects in loop
// remove this line, and the sentence will be valid after loop
NSAutoreleasePool *innerPool = [[NSAutoreleasePool alloc] init];
myBlock(item, idx++, &doStop);
// drain the pool, autorelease objects from block
[innerPool drain];
if (doStop) {
break;
}
}
// faults if we drained the pool
// Program received signal: "EXC_BAD_ACCESS".
NSLog(@"Sentence is %@",sentence);
[pool drain];
return 0;
}
innerPool
object, then the code works as I originally expected, and presumably the NSRunLoop
pool will eventually clean up the various NSString
objects.