

お願いします。  
循環参照を防ぐための、弱い参照の使い方でいろいろと試しています。弱い参照のみで参照してるオブジェクトが解放されないように思える現象があり、質問させて頂きます。  
（アップルのPrograming with Objective-Cの中のpropertyのところを参考にしています）

[code]

    //date1に現在の時刻を参照させる。（強い参照で）
    NSDate *date1 = [[NSDate alloc] init];　
    
    //date2にも同じ時刻を参照させる。（弱い参照で）
    NSDate * __weak date2 = date1;　
    
    //date1に別の時刻を参照させる。（最初に参照していた現在の時刻への強い参照はなくなる）
    date1 = [[NSDate alloc] initWithString:@"2000-01-01 00:00:00 +0000"];  
    
    NSLog(@"date1 is %@", date1);　//date1は変更後の時刻(2000年1月1日)を参照
    NSLog(@"date2 is %@", date2);　//date2はnullになる
    
[/code]

上記のようにdate2を弱い参照にすると、date1の参照先が変わるとdate2がnullになることが  
確認できました。（強い参照だと現在の時刻を保持します）しかし、１行目のコードを日付を指定してNSDateを生成するコードに変更すると、例えば、

[code]

    NSDate *date1 = [[NSDate alloc] initWithString:@"2000-12-31 23:59:59 +0000"];
    
[/code]

とするとdate1の参照先が変わってもdate2はこの日付を保持し、nullになりません。なぜでしょうか。また扱うデータの型をNSString型にしても、同じように弱い参照のみで参照しているオブジェクトが解放されないようです。よろしくお願いします。


CC BY-SA 3.0
2015-09-06T08:00:44.750
16303
2015-09-06T15:01:51.247
2015-09-06T12:50:26.853
7362
12218
question
objective-c arc
強い参照、弱い参照について

[code]

    NSLog(@"%d", (int)CFGetRetainCount((__bridge CFTypeRef)date1));
    
[/code]

で参照カウンタを見れば分かりますが、`initWithString:`で生成した`NSDate`は`-1`（解放不要）が返却されます。

弱参照がゼロ化される条件は、ランタイムが管理しているオブジェクト毎の参照カウントが0になった場合なので、解放されないオブジェクトに対しては`__weak`は機能しません。

同じ`NSDate`でも挙動が違うのは、クラスクラスタにより生成されるクラスそのものが違うためです。

[code]

    [[NSDate alloc] init];
    
[/code]

で生成されるのは、`__NSDate`です。対して、

[code]

    [[NSDate alloc] initWithString:@"2015-09-06 00:00:00 +0000"];
    
[/code]

で生成されるクラスは`__NSTaggedDate`です。

* * *

ここからはフレームワークのプライベート領域なので推測でしかないのですが、`__NSTaggedDate`はタグ付きポインタで実装されているのだと思われます（同様の推察はいろいろ出てきます）。

タグ付きポインタを使うメリットは、ポインタの余った`bit`に日付情報を持たせることで、単一のインスタンスで複数の日付を表現できる、ヒープに優しい実装にできることです。


CC BY-SA 3.0
2015-09-06T10:23:08.897
16306
2015-09-06T15:01:51.247
2015-09-06T15:01:51.247
5337
5337
16303
answer