2012/04/14

Objective-C:雖然NSString是唯讀的,但內容還是可能改變

在Objective-C裡,很多類別常常有唯讀版與可變版,譬如NSString與NSMutableString、NSArray與NSMutableArray、NSDictionary與NSMutableDictionary,一般來說,唯讀版的物件建立之後就不能改變,可變版的物件建立後,可以隨心所欲地進行修改。

一旦建立出NSString物件,NSString類別並沒有提供任何方法讓我們修改其中的字串,但要小心,裡頭的字串還是有可能會改變的,以底下範例說明。

假設有個Person類別,有兩個屬性name(名字)與address(住址)。其中name屬性使用retain,address使用copy,也就是說,當你指定一個NSString物件給name時,它只會記住該物件指標並增加參考計數,而指定一個NSString物件給address時,它會傳送copy訊息給該物件,得到一份拷貝。

// Person.h
#import <Foundation/Foundation.h>

@interface Person : NSObject
{
    NSString *name;
    NSString *address;
}

@property (nonatomic, retain) NSString *name;
@property (nonatomic, copy) NSString *address;

@end


// Person.m
#import "Person.h"

@implementation Person
@synthesize name;
@synthesize address;

-(NSString *)description
{
    return [NSString stringWithFormat:@"name(%@), address(%@)", name, address];
}

@end


// main.m
#import <Foundation/Foundation.h>
#import "Person.h"

int main (int argc, const char * argv[])
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   
    NSMutableString *sname = [NSMutableString stringWithString:@"Amanda"];
    NSMutableString *aname = [NSMutableString stringWithString:@"Taiwan"];
   
    Person *person = [[Person alloc] init];

    person.name = sname;
    person.address = aname;
    NSLog(@"1: person=%@", person);
   
    [sname appendString:@"XXX"];
    [aname appendString:@"YYY"];
    NSLog(@"2: person=%@", person);
   
    [person release];
    [pool release];
    return 0;
}

首先建立兩個NSMutableString物件sname與aname,分別指定給person物件的name與address,然後印出person物件。接下來以NSMutableString介面修改sname與aname,然後再印出person物件,你會發現,person的name變了,address沒變。

程式輸出如下:

2012-04-14 23:01:47.603 TestNSString[24655:903] 1: person=name(Amanda), address(Taiwan)
2012-04-14 23:01:47.606 TestNSString[24655:903] 2: person=name(AmandaXXX), address(Taiwan)

結論,不要以為的物件的類別為NSString就不會改變,若要確保不變,屬性可使用copy宣告。

No comments:

Post a Comment