2011-08-24 32 views
8

Các mã sau bị treo, vì nội dung của sentence biến mất khi khối cuối cùng thoát ra.Gán các đối tượng cho biến bên ngoài một khối

#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; 
} 

Cách chính xác/thành ngữ để thực hiện công việc này là gì?

+0

Wow, thật lạ lùng, tôi không chắc tại sao điều đó không hiệu quả. – jtbandes

+0

Tôi đã thấy mọi người làm một '[[someVariable retain] autorelease]' ở cuối khối để trả lại mọi thứ, nhưng tôi không chắc tại sao điều đó lại tạo nên sự khác biệt nếu như tôi nghi ngờ, một nhóm tự động chạy. Tôi không biết, đó là lý do tại sao tôi hỏi, và có tất cả các loại bài viết về việc sao chép các khối, và truyền đi chúng xung quanh, nhưng không có gì mà tôi có thể tìm thấy trên một thứ đơn giản, như thế này. –

+0

Lỗi/ngoại lệ bạn nhận được là gì? – nacho4d

Trả lời

4

Ok, tôi đã đi và chơi với Xcode một chút, và đây là một mô hình của những gì đang xảy ra, mà dường như phù hợp với những gì tôi nhìn thấy.

Khối tôi đã sử dụng trên là không làm bất cứ điều gì đặc biệt, nhưng enumerateObjectsUsingBlock mã xuất hiện để có riêng của mình NSAutoreleasePool, do đó có vẻ là những gì đã gây dealloc được gọi trên đối tượng alloc'ed, nhưng autoreleased bên trong khối.

Các mã sau đây phù hợp với hành vi những gì tôi nhìn thấy ở trên:

#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; 
} 

Nếu tôi loại bỏ các đối tượng innerPool, sau đó mã hoạt động như tôi dự kiến ​​ban đầu, và có lẽ các hồ bơi NSRunLoop cuối cùng sẽ dọn dẹp các đối tượng khác nhau NSString.

LƯU Ý: chủ đề này bây giờ là số 2 Google kết quả cho 'enumerateObjectsUsingBlock autorelease':

Google 'enumerateObjectsUsingBlock+autorelease'

Kết quả đầu tiên khẳng định câu trả lời này. Cảm ơn tất cả.

1

Ok vì vậy tôi không chắc chắn 100% những gì đang xảy ra ở đó nhưng trong thời gian trung bình nó hoạt động nếu bạn thay đổi

NSArray *items = [NSArray arrayWithObjects:@"why ", @"must ", @"this ",nil]; 
NSMutableString *sentence = [[NSMutableString alloc] init]; 
[items enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) 
{ 
    [sentence appendFormat:@"%@",obj]; 
}]; 

NSLog(@"Sentence is %@",sentence); 

[sentence release]; sentence = nil; 

Cập nhật nhờ @ nacho4d

+1

Tôi trường hợp này tôi nghĩ là không cần thiết sửa đổi '__block'. Và đừng quên để '[câu phát hành]' của khóa học :) – nacho4d

+0

Ah có tốt bắt trên cả hai –

+0

Cảm ơn, tôi đã sử dụng một cái gì đó như thế ở một nơi khác, nhưng tôi đang cố gắng để làm việc ra làm thế nào để có được các đối tượng, phân bổ trong một khối, ra khỏi một khối mà không có chúng biến mất. Đoạn mã trên chỉ là điều đơn giản nhất mà tôi có thể nghĩ đến để chứng minh điều gì đó mà tôi không hiểu.Tất nhiên viết mã như thế này bằng cách sử dụng 'NSMutableString' là hiệu quả hơn anyway, nhưng tôi chỉ muốn một chút đơn giản của mã demo. Cảm ơn. –

1

Như bạn nói, tôi nghi ngờ điều này đang gặp lỗi khi chạy autorelease pool, vì nó có thể làm trong enumerateObjectsUsingBlock:. Điều này sẽ gây phiền nhiễu khi làm việc xung quanh nếu bạn có biến số __block. Bạn có thể sử dụng một NSMutableString thay vào đó, hoặc đơn giản là làm được điều này, đó là sạch anyway:

for (id obj in items) 
{ 
    sentence = [sentence stringByAppendingFormat:@"%@",obj]; 
} 

Ngoài ra, nếu bạn sử dụng ARC, trình biên dịch nên loại bỏ những vấn đề đối với bạn.

Các vấn đề liên quan