UIImage преобразуется в NSData загадочно - PullRequest
0 голосов
/ 12 января 2012

Пожалуйста, взгляните на эти две простые части кода. Это

- (void)testMethod
{

NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:@"myEncodedObjectKey"];
self         = (Profile *) [NSKeyedUnarchiver unarchiveObjectWithData:data];

for (int i = 0; i < self.avatar.count; i++)
    [self.avatar replaceObjectAtIndex:i withObject:[UIImage imageWithData:[self.avatar objectAtIndex:i]]];

if ([[self.avatar objectAtIndex:0] isKindOfClass:[UIImage class]])
    NSLog(@"UIImage");//at this moment it's UIImage
}

и это:

[currentProfile testMethod];

if ([[currentProfile.avatar objectAtIndex:0] isKindOfClass:[NSData class]])
    NSLog(@"NSData");//Moment later it is NSData

В первом я выбираю пользовательский объект из NSUserDefaults и работаю с переменной NSMutableArray с именем "avatar". Я конвертирую каждый его объект из NSData в UIImage. Затем я проверяю, что у меня есть, используя NSLog. Это UIImage. Во втором фрагменте кода вы можете увидеть, как через мгновение то, что было UIImage, возвращается к NSData по собственной воле. Похоже, я четко описал свою проблему. Вы понимаете, что происходит? Я не. Заранее большое спасибо за внимание

1 Ответ

2 голосов
/ 12 января 2012

Почему вы меняете собственный объект в вашем -testMethod методе?Это крайне недопустимо.

На самом деле вы устанавливаете локальную переменную self, которая передается в качестве параметра вашему методу, в новое значение.Это означает, что вы не редактируете получатель метода, вы просто редактируете свой параметр.

Когда ваш метод вызывается во время выполнения, вызывается функция C objc_msgSend():

// Declaration of objc_msgSend
id objc_msgSend(id receiver, SEL selector, ...);

Теперь, когда вы вызываете свой метод ...

[myInst testMethod];

... это то, что фактически вызывается во время выполнения:

objc_msgSend(myInst, @selector(testMethod));

Вы уже видите, что происходит?В реализации вашего метода переменная self установлена ​​на первый аргумент objc_msgSend.Когда вы переназначаете self, ваш не редактирует содержимое переменной myInst и, таким образом, вы не редактируете исходный экземпляр, который вы передали.Вы просто устанавливаете myInst, он же self, локальную переменную, на ваш известный указатель.Вызывающий функцию не заметит изменения.

Сравните ваш код со следующим кодом C:

void myFunction(int a) {
    a = 3;
}

int b = 2;
myFunction(b);
printf("%d\n", b);
// The variable b still has the original value assigned to it

Приведенный выше код делает то же, что и вы:

// Variation on objc_msgSend
void myMethodWrittenInC(id myInst) {
    // Local variable changes, but will not change in the calling code
    myInst = nil;
}

MyClass *myObj;

myObj = [[MyClass alloc] init];
myMethodWrittinInC(myObj);
// At this point myObj is not nil

И, наконец, вот что вы делаете:

- (void)testMethod
{

    NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:@"myEncodedObjectKey"];
    // You assign the local variable self (passed as an invisible argument
    // to your method) to your new instance, but you do not edit the original 
    // instance self pointed to. The variable currentProfile does not change.
    self = (Profile *) [NSKeyedUnarchiver unarchiveObjectWithData:data];

    for (int i = 0; i < self.avatar.count; i++)
        [self.avatar 
         replaceObjectAtIndex:i 
         withObject:[UIImage imageWithData:[self.avatar objectAtIndex:i]]];

    if ([[self.avatar objectAtIndex:0] isKindOfClass:[UIImage class]])
        NSLog(@"UIImage");//at this moment it's UIImage
}


// (1) Here currentProfile points to an instance of your class
[currentProfile testMethod];
// (2) it calls the method, but the local variable does not change
// and still points to the same instance.

if ([[currentProfile.avatar objectAtIndex:0] isKindOfClass:[NSData class]])
    NSLog(@"NSData");//Moment later it is NSData
...