4

BKObject はカスタム オブジェクトであり、複数の BKObject を配列に入れたいと考えています。

BKViewController:

#import <UIKit/UIKit.h>
#import "BKObject.h"

@interface BKViewController : UIViewController

@property (strong, nonatomic) NSArray *data;
@property (weak, nonatomic) BKObject *tmpObject;

@end

BKViewController.m:

#import "BKViewController.h"

@implementation BKViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSMutableArray *arr = [[NSMutableArray alloc] init];
    for(NSInteger i = 0; i < 100000; i++){
        [arr addObject:[[BKObject alloc] initWithName:@""]];
    }

    self.data = [NSArray arrayWithArray:arr];

    __weak BKObject *weakMutableObject = arr[0];
    [arr removeAllObjects];
    NSLog(@"%@", weakMutableObject); // print out the object, why?

    __weak BKObject *weakObject = self.data[0];
    self.data = nil;
    NSLog(@"%@", weakObject); // print out the object again, but why?


    self.tmpObject = [[BKObject alloc] initWithName:@""];
    NSLog(@"%@", self.tmpObject); // print null, very clear

}


@end

最初の 2 つの NSLog メッセージが (最後の NSLog のように) null ではなくオブジェクトを表示する理由に興味があります。iOS 7 SDK で最新の Xcode 5.0.1 を使用しています。

4

5 に答える 5

2

この行で:

self.data = [NSArray arrayWithArray:arr];

最終的に、2 つの配列と、オブジェクトへの 2 つの強い参照が作成されます。次に、最初の配列からオブジェクトを削除しますが、2 番目の配列からは削除しません。したがって、オブジェクトはまだ 1 つの強力な参照を持ち、まだ生きています。

オブジェクトへのすべての強い参照が削除されると、__weakはゼロになることに注意してください。2 番目の配列では、最初の.NSLog

2 番目NSLogの では、配列がすぐに解放されないようにするプロパティへのアクセスに関連する自動解放がおそらくあります。編集:詳細については、Rob Napier の回答を参照してください。

3 番目のログでは、次のように設定しています。

self.tmpObject = [[BKObject alloc] initWithName:@""];

self.tmpObject弱い参照はどこにありますか。このオブジェクトへの弱い参照しかないため、プロパティはすぐにゼロになります。

于 2013-10-26T17:53:41.207 に答える
0

おそらく、あなたがまだ同じ自動解放プール内にいるためです。これはあなたの機能に限定されています。関数の範囲外で弱参照を設定し (プロパティとしてなど)、関数を呼び出して別の関数内で作成および解放すると、オブジェクトが解放されます。

例のようにループ内で多くのオブジェクトを作成してリリースする場合は、カスタム リリース プール内で行うことを検討してください。

見てください: https://developer.apple.com/library/mac/documentation/cocoa/conceptual/memorymgmt/articles/mmAutoreleasePools.html

于 2013-10-26T17:51:18.367 に答える
0

問題は、配列値を変数に割り当ててから配列を削除しているが、nslog で配列を割り当てた変数を出力していることです。したがって、間違いなくnullを出力せず、オブジェクトを出力します

  self.data = [NSArray arrayWithArray:arr];

__weak BKObject *weakMutableObject = arr[0];
[arr removeAllObjects];
NSLog(@"%@", weakMutableObject); // print     
out the object, why?

このような便利なコンストラクターの戻り値は、自動解放されたオブジェクトでなければなりません*。これは、現在の autoreleasepool がオブジェクトを保持しており、プールが空になるまでオブジェクトを解放しないことを意味します。したがって、このオブジェクトが少なくともメソッドの実行中に存在することはほとんど保証されていますが、おそらくこの動作に依存するべきではありません。

于 2013-10-26T18:07:17.840 に答える
0

これがオブジェクトの仕組みです。メモリ位置が割り当てられたオブジェクトを作成し、それを追跡するローカル NSArray に入れ、最終的にインスタンス変数 (self.data) に入れる前にもう 1 つのローカル配列に入れました。したがって、現時点では、オブジェクトは技術的に保持カウントとして 3 を持っているため、コードで 2 回解放したため、両方の NSLog ステートメントに出力されます。

以下のコードで試してください:

NSString *a = @"1";

NSMutableArray *arr = [[NSMutableArray alloc] init];
for (int i = 0; i < 10000; i++) {
    [arr addObject:a]; // Retain count 1
}

self.myArr = arr; // Retain count 2
NSString *test = arr[0];
[arr removeAllObjects];
NSLog(@"%@", test); // Prints ... Good! Retain count is 1

NSString *test1 = self.myArr[0];
self.myArr = nil;
NSLog(@"%@", test1); // Crash as object gone
于 2013-10-26T18:01:21.477 に答える