请看一下这两段简单的代码。这个
- (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的。好像我清楚地描述了我的问题。你明白发生了什么吗?我不。非常感谢你提前注意
答案 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