UIImage神秘地转换为NSData

时间:2012-01-12 17:50:18

标签: objective-c uiimage nsdata

请看一下这两段简单的代码。这个

- (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获取自定义对象,并使用名为“avatar”的NSMutableArray变量。我将其每个对象从NSData转换为UIImage。然后我通过使用NSLog检查我得到了什么。这是UIImage。在第二段代码中,您可以看到UIImage之后是如何通过自己的意愿转回NSData的。好像我清楚地描述了我的问题。你明白发生了什么吗?我不。非常感谢你提前注意

1 个答案:

答案 0 :(得分:2)

为什么要更改-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