7

Sử dụng phương pháp NSObject -(id)awakeAfterUsingCoder:(NSCoder *)decoder làm ví dụ, tài liệu nói:Mô hình mới để phát hành bản thân với tính năng tham chiếu tự động là gì?

Cho phép một đối tượng, sau khi được giải mã, để thay thế một đối tượng cho chính nó. Ví dụ, một đối tượng đại diện cho một phông chữ có thể, khi được giải mã, tự giải phóng và trả về một đối tượng hiện có có cùng một mô tả phông chữ giống như chính nó . Bằng cách này, các đối tượng thừa có thể bị loại bỏ .

Thông thường bạn sẽ làm gì

[self release]; 
return substitutedObject; 

Với ARC bạn phải rời khỏi dòng này ra. Nó sẽ không bị rò rỉ? Hay tôi chỉ nên tin tưởng đối tượng NSCoder để giải phóng đối tượng gốc cho tôi? Nếu vậy tại sao bạn phải tự giải phóng một cách rõ ràng với mã không phải ARC ở nơi đầu tiên?

Tôi không nghĩ self = nil là chính xác trong ánh sáng của những gì các tài liệu biên dịch nói về bản thân: http://clang.llvm.org/docs/AutomaticReferenceCounting.html#misc.self

Trả lời

2

Như đã lưu ý, bạn không thể viết [self release];. Ngoài ra, awakeAfterUsingCoder:không phải là bộ khởi tạo - bạn không thể gán lại self.

Điều này có bị rò rỉ không?

Có. Chứng minh trong chương trình dưới đây.

Hoặc tôi có nên tin tưởng đối tượng NSCoder để giải phóng đối tượng gốc cho tôi không?

số

Một cách tiếp cận để tránh rò rỉ tồn tại dưới đây - Tôi sẽ không gọi nó là "mô hình mới", chỉ là cách tiếp cận đầu tiên mà đến tâm trí. Nó bao gồm một phiên bản rõ ràng của self và trong trường hợp này một rõ ràng giữ của kết quả:

#import <Foundation/Foundation.h> 

@interface MONBoolean : NSObject <NSCoding> 

- (id)initWithBool:(bool)pBool; 

- (bool)isTrue; 
- (bool)isFalse; 

@end 

static NSString * const MONBoolean_KEY_value = @"MONBoolean_KEY_value"; 

@implementation MONBoolean 
{ 
    bool value; 
} 

- (id)initWithBool:(bool)pBool 
{ 
    self = [super init]; 
    if (0 != self) { 
     value = pBool; 
    } 
    return self; 
} 

- (bool)isTrue 
{ 
    return true == value; 
} 

- (bool)isFalse 
{ 
    return false == value; 
} 

- (NSString *)description 
{ 
    return [[NSString alloc] initWithFormat:@"<%s:%p> : %s", object_getClassName(self), self, self.isTrue ? "true" : "false"]; 
} 

- (void)encodeWithCoder:(NSCoder *)aCoder 
{ 
    [aCoder encodeBool:value forKey:MONBoolean_KEY_value]; 
} 

- (id)initWithCoder:(NSCoder *)aDecoder 
{ 
    self = [super init]; 
    if (0 != self) { 
     value = [aDecoder decodeBoolForKey:MONBoolean_KEY_value]; 
    } 
    return self; 
} 

- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder 
{ 
    const bool b = value; 
    // cannot reassign self outside of an initializer. 
    // if not released, will result in a leak: 
    CFRelease((__bridge const void*)self); 
    MONBoolean * result = [[MONBoolean alloc] initWithBool:b]; 
    // now we have to retain explicitly because this is 
    // an autoreleasing method: 
    CFRetain((__bridge const void*)result); 
    return result; 
} 

@end 

int main(int argc, const char * argv[]) 
{ 
    @autoreleasepool { 
     MONBoolean * a = [[MONBoolean alloc] initWithBool:true]; 
     NSData * data = [NSKeyedArchiver archivedDataWithRootObject:a]; 
     MONBoolean * b = [NSKeyedUnarchiver unarchiveObjectWithData:data]; 
     NSLog(@"%@", b); 
    } 
    system("leaks NAME_OF_PROCESS_HERE"); 
    return 0; 
} 
+0

Bạn có thể làm rõ lý do tại sao bạn phải giữ lại kết quả một cách rõ ràng không? Chắc chắn đánh bại mục đích của ARC. Cảm ơn bạn đã trả lời mọi thứ khác. – jamesmoschou

+0

@moshy bạn được chào đón. có - tôi ban đầu bỏ qua chi tiết đó. lý do là 'awakeAfterUsingCoder:' trả về tham chiếu không sở hữu (hoặc tự động phát hành). như vậy, ARC chèn một số giảm ref cho chúng tôi cho giá trị trả về của chúng tôi. những gì chúng tôi muốn làm là chuyển giao * một cách hiệu quả từ một đối tượng này sang đối tượng khác. tôi chạy nó trong các dụng cụ - không bị rò rỉ. không có zombie. mà không có sự giữ lại rõ ràng, một zombie sẽ được gửi đi. mà không có bản phát hành rõ ràng - rò rỉ. thử nó cho chính bạn (đặt khối '@ autorelease' trong một' while (1) '). – justin

+1

Bạn có thể đặt phương thức thành viên của họ «init' với' __attribute __ ((objc_method_family (init))) 'và sau đó gán lại' self'? –

0

Tôi tin ARC là đủ thông minh để theo dõi tất cả các đối tượng. Vì vậy, bạn sẽ có thể chỉ cần không nói bất cứ điều gì về bộ nhớ và các ứng dụng sẽ phát hành các đối tượng khi nó không còn sử dụng. Chạy nó thông qua các hồ sơ rò rỉ, chỉ trong trường hợp, nhưng nó sẽ không sao.

+4

Nhưng sự hiểu biết của tôi là tính toán tham chiếu tự động vẫn chỉ là tính tham chiếu. Nó không giống như thu gom rác thải. Do đó, vẫn còn (về mặt lý thuyết) có thể có các vật bị rò rỉ khi chúng không còn sử dụng nữa. Tôi sẽ chạy nó thông qua profiler. – jamesmoschou

4

Một vấn đề tương tự phát sinh trong bối cảnh NIB vật cấp cao nhất trên Mac OS X. Resource Programming Guide nói:

Nếu Chủ đầu tư của tập tin không phải là một thể hiện của NSWindowController hoặc NSViewController, thì bạn cần phải giảm các số tham chiếu của cấp cao nhất các đối tượng chính mình. Với tính năng tham chiếu thủ công, có thể đạt được điều này bằng cách gửi các đối tượng cấp cao nhất một thông báo release. Bạn không thể làm điều này với ARC. Thay vào đó, bạn đưa tham chiếu đến các đối tượng cấp cao nhất vào loại Nền tảng lõi và sử dụng CFRelease.

Vì vậy, kỹ thuật đó có thể được sử dụng trong tình huống này. CFRelease((__bridge CFTypeRef)self);

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