为什么更改字典中包含的可变数组不需要更新字典?

时间:2012-07-21 19:36:32

标签: objective-c cocoa-touch collections

我正在尝试CS193P课程(Objective-C)中的一段代码。我注意到编译器的工作方式。名为NSMutableArray的{​​{1}}已添加到photosNSMutableDictionary。稍后,对photosByPhotographer进行了更改,对photos没有任何更改。当我记录photosByPhotographer时,更改会自动应用于它,并且不需要任何额外的代码行!

我想知道编译器是如何使这个工作的?有什么材料可供阅读吗?

代码如下:

photosByPhotographer

- (void)updatePhotosByPhotographer { NSMutableDictionary *photosByPhotographer = [NSMutableDictionary dictionary]; for (NSDictionary *photo in self.photos) { NSString *photographer = [photo objectForKey:FLICKR_PHOTO_OWNER]; NSMutableArray *photos = [photosByPhotographer objectForKey:photographer]; if (!photos) { photos = [NSMutableArray array]; [photosByPhotographer setObject:photos forKey:photographer]; NSLog(@"photosByPhotographer in if: %@", photosByPhotographer); } [photos addObject:photo]; NSLog(@"photosByPhotographer after if: %@", photosByPhotographer); } self.photosByPhotographer = photosByPhotographer; } 结果如下:

NSLog()

4 个答案:

答案 0 :(得分:5)

那是因为在Cocoa中,你正在使用对象并通过引用传递。

想象一下这段代码:

NSMutableArray *a, *b;

a  = [NSMutableArray new];
[a addObject:@"A"]; // a contains @"A"
b = a; // b is assigned to the same object
[b addObject:@"B"]; // a and b contain @"A", @"B"

NSLog(@"a = %p and b = %p", a, b); // same values

变量ab 指向到同一个对象。您还可以通过比较指针值来查看。

但是,如果我们执行以下操作:

NSMutableArray *a, *b;

a  = [NSMutableArray new];
[a addObject:@"A"]; // a contains @"A"
b = [[a mutableCopy] autorelease]; // b is assigned to a COPY of the object
[b addObject:@"B"]; // b contains @"A", @"B", while a still contains @"A"

NSLog(@"a = %p and b = %p", a, b); // NOT the same values

b被分配给a(不是原始版本)的副本,因此b指向其他对象。您可以通过比较对象的地址进行检查。

答案 1 :(得分:3)

photos数组通过引用存储在NSDictionary中,而不是作为副本存储。因此,如果更改基础数组,则会在访问字典时看到。

这就是为什么通过引用提供一些可变类型而不是存储它们的副本是危险的。

答案 2 :(得分:3)

您需要了解指针和引用的工作原理。基本上,而不是代码中的变量是实际的完整结构和对象,通常它们是对这些结构的引用或指针。您可以通过多种方式可视化概念,但也许有用的是想到变量,例如:

NSDictionary *myDict;

实际上只是一个数字,它是myDict对象的内存地址。以下是其工作原理的可视化:

enter image description here

您的NSDictionary引用指向内存中的对象,该对象本身包含对其他对象的多个引用,可以在不影响字典本身的情况下对其进行更改。在这个例子中,我展示了NSArray添加了一个新对象。字典中对数组的引用保持不变。在任何时候,只有一个数组实例及其中的对象。

答案 3 :(得分:0)

当您在NSLog对象上调用NSDictionary时,会调用其方法description

在方法description的实现中,NSDictionary正在调用其所有键的每个值(对象)的description方法。 因此,当值(对象)发生变化时,其description方法的输出也会发生变化。 这就是为什么在再次调用NSLog对象上NSDictionary时会反映出来的原因。