问题
I was trying a piece of code from CS193P course (Objective-C). I noticed something in the way that the compiler works. An NSMutableArray
called photos
was added to an NSMutableDictionary
, photosByPhotographer
. Later on, a change was made to photos
without any changes to photosByPhotographer
. When I logged photosByPhotographer
, the change was automatically applied to it and it did not need any extra lines of code!
I wonder how the compiler makes this work? Any materials to read from?
The code is as follows:
- (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;
}
The NSLog()
result is as follows:
2012-07-20 20:05:57.618 Shutterbug[453:f803] photosByPhotographer in if: {
Dowbiggin = (
);
}
2012-07-20 20:05:57.620 Shutterbug[453:f803] photosByPhotographer after if: {
Dowbiggin = (
{
accuracy = 16;
context = 0;
dateupload = 1342836026;
description = {
"_content" = "";
};
farm = 9;
"geo_is_contact" = 0;
"geo_is_family" = 0;
"geo_is_friend" = 0;
"geo_is_public" = 1;
id = 7612787270;
isfamily = 0;
isfriend = 0;
ispublic = 1;
latitude = "37.307085";
longitude = "-121.900395";
originalformat = jpg;
originalsecret = 052e70d412;
owner = "22751315@N05";
ownername = Dowbiggin;
"place_id" = cils8sJUV7MeXHwt9A;
secret = 4437007c99;
server = 8161;
tags = "square squareformat iphoneography instagramapp uploaded:by=instagram foursquare:venue=49f13597f964a5209c691fe3";
title = "My little goofball";
woeid = 55971033;
}
);
}
回答1:
That's because in Cocoa, you are using objects and pass by reference.
Imagine this code:
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
The variables a
and b
point to the same object. You can also see that by comparing the pointer values.
However, if we do the following:
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
is assigned to a copy of a
(not the original), so b
points to an other object. You can check by comparing the addresses of the objects.
回答2:
The photos
arrays is stored by reference in the NSDictionary, not as a copy. Therefore, if you change the underlying array, you will see that when you access the dictionary.
This is why it can be dangerous to provide some mutable types by reference instead of storing copies of them.
回答3:
You need to understand how pointers and references work. Basically rather than variables in your code being actual full structures and objects, generally they are references or pointers to those structures. You can visualise the concept in a number of ways, but perhaps one that's useful is to think of a variable such as:
NSDictionary *myDict;
being really just a number which is the memory address of the myDict object. Here's a visualisation of how it works:

Your NSDictionary
reference points to an object in memory which itself holds multiple references to other objects, which can be changed without affecting the dictionary itself. In this example I've shown an NSArray
having a new object added to it. The reference to the array from the dictionary remains the same. There is only ever one instance of the array and the objects in it at any time.
回答4:
When you call NSLog
on an NSDictionary
object then its method description
is called.
In the implementation of the method description
, NSDictionary
is calling the description
method of each value (object) of all its keys.
So when a value (object) changes so does the output of its description
method change.
That is why it is reflected when calling NSLog
on an NSDictionary
object again.
来源:https://stackoverflow.com/questions/11595303/why-does-changing-a-mutable-array-contained-in-a-dictionary-not-require-updating