2013-01-02 36 views
9

thể trùng lặp:
Why do weak NSString properties not get released in iOS?Objective-C: attritube yếu không làm việc như mong đợi

Tôi là một newbie để Objective C và tôi đã có một số câu hỏi mà tôi không thể tự trả lời. Tôi có một khối mã cho biến thử nghiệm __weak (Tôi đang sử dụng ARC, tất nhiên):

NSString *myString = [[NSString alloc] initWithFormat:@"John"]; 
NSString * __weak weakString = myString; 
myString = nil; //<-- release the NSString object 
NSLog(@"string: %@", weakString); 

Sản lượng của các mã trên được như mong đợi, vì weakString là một biến yếu:

2013-01-02 11:42:27.481 ConsoleApp[836:303] string: (null) 

Nhưng khi tôi sửa đổi mã này:

NSString *myString = [[NSString alloc] initWithFormat:@"John"]; 
NSString * __weak weakString = myString; 
NSLog(@"Before: %@", weakString); //<--- output to see if the __weak variable really works. 
myString = nil; 
NSLog(@"After: %@", weakString); 

Đầu ra là hoàn toàn không phải là điều tôi mong đợi:

2013-01-02 11:46:03.790 ConsoleApp[863:303] Before: John 
2013-01-02 11:46:03.792 ConsoleApp[863:303] After: John 

Kết quả của NSLog sau phải là (nil) thay vì "John". Tôi đã cố gắng để tìm kiếm trong nhiều tài liệu nhưng tôi đã không tìm thấy câu trả lời cho trường hợp này. Ai đó có thể đưa ra giải thích hợp lý không? Cảm ơn trước.

+0

@jrturton: Tôi không nghĩ đây là bản sao của câu hỏi được liên kết. Vấn đề ở đó là sử dụng 'NSString' không đổi mà không tham gia vào việc quản lý bộ nhớ thông thường vì tối ưu hóa hiệu suất. Áp phích ở đây sử dụng 'initWithFormat' để tránh chính xác vấn đề này. – zoul

+0

Tôi đã đọc (nhưng không thể tìm thấy thời gian này) một lần nữa của việc này, nơi một số tối ưu hóa của NSString ngăn chặn điều này làm việc. Nếu OP thử một loại đối tượng khác, tôi nghi ngờ mọi thứ sẽ hoạt động như mong đợi. Tôi sẽ tiếp tục tìm kiếm ... – jrturton

+0

Cũng ở đây: http://stackoverflow.com/questions/9202810/lifetime-of-weak-local-variables-with-arc – jrturton

Trả lời

6

Chức năng NSLog đang giữ lại NSString được truyền trong một bể tự động. Biến zeroing-weak do đó sẽ không được zeroed cho đến khi vùng tự động thoát ra. Ví dụ:

__weak NSString* weakString = nil; 

@autoreleasepool { 
    NSString* myString = [[NSString alloc] initWithFormat:@"Foo"]; // Retain count 1 
    weakString = myString;   // Retain count 1 
    NSLog(@"A: %@", weakString); // Retain count 2 
    NSLog(@"B: %@", weakString); // Retain count 3 
    myString = nil;    // Retain count 2 
    NSLog(@"C: %@", weakString); // Retain count 3 

    NSAssert(weakString != nil, @"weakString is kept alive by the autorelease pool"); 
} 

// retain count 0 
NSAssert(weakString == nil, @"Autorelease pool has drained."); 

Tại sao NSLog đặt chuỗi vào một nhóm tự động phát hành? Đó là một chi tiết thực hiện.

Bạn có thể sử dụng trình gỡ lỗi hoặc Công cụ để theo dõi số lần giữ lại của cá thể NSString. Số lượng giữ lại chính xác là không quan trọng, nhưng nó làm sáng tỏ một số điều về những gì đang diễn ra đằng sau hậu trường. Điều quan trọng là trường hợp NSString được deallocated khi các hồ bơi autorelease được thoát.

+1

Vâng, điều này khá nhiều giải thích nó, tôi đã nghĩ rằng NSlog() sẽ tăng số lượng giữ lại của tham số của nó (s), nhưng câu trả lời của bạn là hợp lý hơn nhiều. Cảm ơn Darren rất nhiều. –

0

Tôi nghĩ rằng đó chỉ là một số chi tiết triển khai. Biến yếu của bạn bị xóa, nhưng không chỉ ngay lập tức. Ví dụ: hoạt động như mong đợi:

NSString *myString = [[NSString alloc] initWithFormat:@"John"]; 
NSString * __weak weakString = myString; 
@autoreleasepool { 
    NSLog(@"Before: %@", weakString); 
    myString = nil; 
} 
NSLog(@"After: %@", weakString); // nil 
Các vấn đề liên quan