Изменение указателя себя - PullRequest
1 голос
/ 11 мая 2010

У меня есть объект, который я выделяю / инициализирую, как обычно, просто чтобы получить экземпляр. Позже в моем приложении я хочу загрузить состояние с диска для этого объекта. Я полагаю, что могу разархивировать свой класс (который соответствует 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)

Чего мне не хватает?

Ответы [ 2 ]

6 голосов
/ 11 мая 2010

Не делай этого. Помимо того, что это нарушает правила идентификации, вы не можете изменять значения указателя, которые удерживаются другими частями программы.

Лучше было бы использовать идиому PIMPL: ваш класс содержит указатель на объект реализации, а вы только меняете его местами.

например. что-то вроде этого:

@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
5 голосов
/ 11 мая 2010

self - аргумент функции для методов экземпляра. Назначение self вполне разумно, точно так же, как назначение значений другим аргументам функции совершенно разумно. Поскольку область действия self является текущей функцией, ваш код пропускает один объект и освобождает другой таким образом, что, скорее всего, произойдет сбой.

Единственное время, которое имеет смысл присвоить self, - это метод init. Хотя он почти никогда не используется, методам init разрешено освобождать себя и выделять новый объект для возврата или просто вернуть nil. Единственная причина, по которой это работает, заключается в том, что возвращаемое значение равно self, и вызывающие init ожидают использовать возвращаемое значение.

Как указал gf, правильный подход - это функция загрузки, которая назначает новые значения членам вашего экземпляра, а не пытается заменить экземпляр.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...