2010-05-10 58 views
1

我有一個對象,我正常分配/ init像獲得一個實例。後來在我的應用程序中,我想從磁盤加載該對象的狀態。我想我可以解開我的課程(符合NSCoding),並且只是在我的實例指向的地方交換。爲此我使用此代碼...改變自己的指針

NSString* pathForDataFile = [self pathForDataFile]; 
if([[NSFileManager defaultManager] fileExistsAtPath:pathForDataFile] == YES) 
{ 
    NSLog(@"Save file exists"); 
    NSData *data = [[NSMutableData alloc] initWithContentsOfFile:pathForDataFile]; 
    NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; 
    [data release]; 

    Person *tempPerson = [unarchiver decodeObjectForKey:@"Person"]; 
    [unarchiver finishDecoding]; 
    [unarchiver release]; 

    if (tempPerson) 
    { 
     [self release]; 
     self = [tempPerson retain]; 
    } 
} 

現在,當我撒一些NSLogs在我的應用我注意到

self.person: <Person: 0x3d01a10> (After I create the object with alloc/init) 
self: <Person: 0x3d01a10> (At the start of this method) 
tempPerson: <Person: 0x3b1b880> (When I create the tempPerson) 
self: <Person: 0x3b1b880> (after i point self to the location of the tempPerson) 
self.person: <Person: 0x3d01a10> (After the method back in the main program) 

我缺少什麼?

回答

5

self是實例方法的函數參數。賦值給自己是完全合理的,就像賦值給其他函數參數一樣是完全合理的。由於self的範圍是當前函數,因此您的代碼會泄漏一個對象並以最有可能導致崩潰的方式釋放另一個對象。

唯一有意義分配給self的方法是使用init方法。雖然它幾乎從未使用,但允許init方法釋放self並分配一個新對象以返回或僅返回nil。這是唯一的原因,因爲返回值是自我的,並且init的調用者期望使用返回值。

正如gf指出的那樣,正確的方法是爲您的實例成員分配新值的加載函數,而不是嘗試替換實例。

+0

這兩個優秀的答案。這個給了我更多的背景,爲什麼我的方法是錯誤的,謝謝! – rob5408 2010-05-10 20:34:46

6

不要這樣做。除了它破壞了身份規則之外,你不能改變程序其他部分的指針值。

更好的方法是使用PIMPL慣用法:您的類包含一個指向實現對象的指針,並且只交換它。

E.g.沿線的東西:

@class FooImpl; 
@interface Foo { 
    FooImpl* impl; 
} 
// ... 
- (void)load; 
@end 

@implementation Foo 
- (void)load { 
    FooImpl* tmp = loadFromDisk(); 
    if (tmp) { 
     FooImpl* old = impl; 
     impl = tmp; 
     [old release]; 
    } 
} 
@end 
+0

謝謝!我會給這個鏡頭。 – rob5408 2010-05-10 20:36:52