スキップしてメイン コンテンツに移動

@property nonatomic strong weak


@propertyの属性にcopyとかstrongとかweakとかあるけど、概念的な説明はどこでもあるけど、具体的な説明をしている記事が少ないので調査した。
Xcode4.3.2時点での内容です。

nonatomic

非スレッドセーフにする。マルチスレッドのものを使わない限りはどんどん指定しよう。
ちなみにatomicな場合は内部的にはgetterは以下のような処理になる模様。ロックが入ってしまう。
[_internal lock];
id result = [[value retain] autorelease];
[_internal unlock];
return result;

getter/setter

getterとsetterのメソッド名はデフォルトで、getterは変数名と同じ、setterはset[Capitalize変数名]だが、それを任意のものに設定することができる。
readonly時にsetterは指定できない(当たり前だが)
通常変更する必要はないが、isなんたら とかってgetterにしたい場合に使うといいらしい。

readwrite/readonly

readwriteはデフォルトなので、単品で指定することはまずない。readonlyはその名の通りsetterが生成されなくなる。self.prop = 1;みたいなドットでのアクセスすらコンパイルエラーになるので、このままだと何もできない変数になる気がする。
.hではreadonlyにして、.mでreadwriteにして定義を上書きすることで、クラス内部では読み書きができ、外部では読み出ししかできないプロパティが出来上がる。
.h
#import <Foundation/Foundation.h>

@interface TestData : NSObject

@property (nonatomic, readonly) NSString* title;

-(void)action;

@end
.m
#import "TestData.h"

// ここがないとactionではエラー
@interface TestData ()
@property (nonatomic, readwrite) NSString* title;
@end

@implementationTestData

@synthesize title;

-(void)action {
    self.title = @"hello";
}

@end

strong/copy/retain/assign

  • ARCを使わない場合はassignがデフォルト、使う場合はstrongがデフォルト。
  • copyとreleaseは、以前の値に対しreleaseが呼ばれる。
  • retainは参照カウントが保持されて、assignは保持されないらしい。
  • copyはNSCopyingプロトコルが実装されていないオブジェクトに対して設定すると落ちる。NSObjectだけだと実装されていないので、使用する際は注意。
  • ARCを無効にしてテスト
TestString.h
#import <Foundation/Foundation.h>

@interface TestString : NSObject <NSCopying>
@property (nonatomic, copy) NSString* string;
-(id)initWithString:(NSString*)string;
@end
TestString.m
#import "TestString.h"

@implementation TestString
@synthesize string;

-(id)initWithString:(NSString*)newString {
    self = [super init];
    self.string = newString;
    return self;
}

- (void)dealloc {
    NSLog(@"dealloc %@", self.string);
    [super dealloc];
}

- (id)copyWithZone:(NSZone *)zone
{
    NSLog(@"duplicate %@", self.string);
    TestString* clone = [[TestString alloc] init];
    [clone setString:self.string];
    return clone;
}

@end
TestData.h
#import <Foundation/Foundation.h>

#import "TestString.h"

@interface TestData : NSObject
@property (nonatomic, [ここを任意に変更]) TestString* title;
@end

TestData.m
#import "TestData.h"

@implementation TestData

@synthesize title;

@end
上記のようなコードがあった場合、[ここを任意に変更]が以下を指定した場合に、
    TestData* data = [[TestData alloc] init];
    TestString* string = [[TestString alloc] initWithString:@"abc"];
    TestString* string2 = [[TestString alloc] initWithString:@"def"];
    [data setTitle:string];
    [data setTitle:string2];
    NSLog(@"end");
    [string release];
    [string2 release];   
    [data release];
というコードを動かした場合、以下のような結果になる。(コメントはその行を通過直後に発生されるログ)
strongは、最後に代入したstring2の所有権がdataに移っているので、外からstring2をreleaseしてもデストラクタが呼ばれない。
copyはcopyなので、外でreleaseするとデストラクタが呼ばれる。またcopyは、自分自身が入れ替わると、入れ替わる前の値はreleaseされるので、setTitle:string2でもデストラクタが呼ばれている。
assignは内部でどう扱おうが知ったことではないという感じ。外でreleaseするとdataのtitleもreleaseされているので、テストコードで言うところの、[data release];の直前でdataのtitleを扱おうとするとEXC_BAD_ACCESSとなる。参照だけを単純に代入すると考えるといい。あとスカラー型はassignでもコピー。
retainは基本的にstrongと同じ。内部的にretainというメソッドがあり、それを使って、「hoge = [fuga retain]」のように代入すると、strongと同じような効果が得られるため、そういうものがあるらしい。
copy
    TestData* data = [[TestData alloc] init];
    TestString* string = [[TestString alloc] initWithString:@"abc"];
    TestString* string2 = [[TestString alloc] initWithString:@"def"];
    [data setTitle:string];             // duplicate abc
    [data setTitle:string2];          // duplicate def, dealloc abc
    NSLog(@"end");                    // end
    [string release];               // dealloc abc
    [string2 release];               // dealloc def
    [data release];
strong
    TestData* data = [[TestData alloc] init];
    TestString* string = [[TestString alloc] initWithString:@"abc"];
    TestString* string2 = [[TestString alloc] initWithString:@"def"];
    [data setTitle:string];
    [data setTitle:string2];
    NSLog(@"end");               // end
    [string release];               // dealloc abc
    [string2 release];   
    [data release];

assign

    TestData* data = [[TestData alloc] init];
    TestString* string = [[TestString alloc] initWithString:@"abc"];
    TestString* string2 = [[TestString alloc] initWithString:@"def"];
    [data setTitle:string];
    [data setTitle:string2];
    NSLog(@"end");               // end
    [string release];                // dealloc abc
    [string2 release];             // dealloc def
    [data release];
retain
    TestData* data = [[TestData alloc] init];
    TestString* string = [[TestString alloc] initWithString:@"abc"];
    TestString* string2 = [[TestString alloc] initWithString:@"def"];
    [data setTitle:string];
    [data setTitle:string2];
    NSLog(@"end");               // end
    [string release];               // dealloc abc
    [string2 release];   
    [data release];

weak

weakはARCを有効にしないと使えない。assignと同等。

コメント

このブログの人気の投稿

日本に来た 今三週間

四月六日に日本に来た、今三週間になった。 嬉しくなかった、悲しくなかった。 日本の携帯電話のカメラはとてもいいよ、私は今撮影が好きだ、いつも寮に帰る途中で花とか魚とか写真を撮る。これも生活の趣味だ。 滴は綺麗だ 桜が凋んで落ちる 天気がいいとき、自転車に乗って、食材を買った。 自分で料理をつくる、おいしそうでしょう。 昨日清水寺に行った、天気はとても熱いね。日に焼けすぎたので、腕は今赤い。 側に花があるので、赤い清水寺はもっと美しそうだ。 木の色は艶やかだ。