3

我正在尝试 CS193P 课程(Objective-C)中的一段代码。我注意到编译器的工作方式。被NSMutableArray调用photos添加到NSMutableDictionary, 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()如下:

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;
    }
);
}
4

4 回答 4

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指向另一个对象。您可以通过比较对象的地址来检查。

于 2012-07-21T19:45:19.687 回答
3

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

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

于 2012-07-21T19:41:35.580 回答
3

您需要了解指针和引用是如何工作的。基本上,代码中的变量不是实际的完整结构和对象,通常它们是对这些结构的引用或指针。您可以通过多种方式可视化该概念,但可能有用的一种方法是考虑一个变量,例如:

NSDictionary *myDict;

实际上只是一个数字,它是 myDict 对象的内存地址。这是它如何工作的可视化:

在此处输入图像描述

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

于 2012-07-21T20:29:17.480 回答
0

当你调用NSLog一个NSDictionary对象时,它的方法description就会被调用。

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

于 2012-07-21T19:53:30.590 回答