3

私は、弱いプロパティと強いプロパティを含む少しの混乱に直面しています。簡潔にするために、コード全体は含めません。

UIView オブジェクトを返すクラス コンビニエンス メソッドを作成し、サブクラス化の代わりに UIView カテゴリに実装しました。

@implementation UIView (CSMonthView)    

+ (UIView *)monthViewFromDateArray:(NSArray *)arrayOfAllShiftsAndEvents withNibOwner:(id)owner selectedDate:(NSDate *)selectedDate withCompletionHandler:(void(^)(CSCalendarButton *selectedButton))block
{   // .. do some stuff
    // Create an instance of UIView
    UIView *monthView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320.0, 200.0)];

    // Create UIButtons and set the passed down 'owner' value, as the target for an
    // action event.

    // Add UIButton as subviews to monthView....

    return monthView;
}

メソッド内には monthView を指すものがないことに注意してください。

CSCalendarViewController というクラスである「所有者」の実装内で、クラス コンビニエンス メソッドを呼び出して上記の UIView を作成し、それを _monthView という UIView プロパティに割り当てます。

@interface CSCalendarViewController : UIViewController 

@property (weak, nonatomic) UIView *monthView;

@end


@implementation CSCalendarViewController


     __weak CSCalendarViewController *capturedSelf = self;
    // Create the current month buttons and populate with values.
    _monthView = [UIView monthViewFromDateArray:_arrayOfAllShiftsAndEvents withNibOwner:self selectedDate:_selectedDate withCompletionHandler:^(CSCalendarButton *selectedButton) {

            capturedSelf.selectedButton = selectedButton;
            [capturedSelf.selectedButton setSelected:YES];
        }

今、私の混乱はこれです。プロパティ「monthView」を弱いものとして定義しましたが、「monthView」は返された UIView の値を保持しています。

先に進んで次のようなことをすると:

    _monthView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 200.0)];

コンパイラーは、「割り当てられた保持オブジェクトが弱い変数に割り当てられました」という警告を (当然のことながら) 表示します。

クラス メソッドから返される UIView に「monthView」を割り当てたときに同じエラー メッセージが表示されないのはなぜですか?

ARC以前のメモリ管理に関しては、私は深く理解していません。また、明らかな何かが欠けていると思います。ありがとう。

4

2 に答える 2

2

「monthView」は、返された UIView の値を引き続き保持します。

それは長くはありません。この質問は、ARC の基本的な仕組みと、まったく新しいメモリ管理システムではなく、従来の保持/解放方法への変換であることを示しています。

プレARC

ARC が登場する前は、弱いまたは強いという概念はありませんでした。代わりに、保持と割り当てを参照していました。変数への割り当ては、参照カウントには何もしませんでした。それを管理するのは開発者次第でした。

現在、メモリ管理ポリシーに関して、名前が「alloc」、「new」、「copy」、または「mutableCopy」で始まるメソッドは、保持されたオブジェクトを返します ( Documentation )。これは、変数への割り当て時に、開発者が明示的に保持する必要がないことを意味しました (明示的にリリースまたは自動解放する必要がありました)。

// Will have a retain count of 1 here 
var = [NSString alloc] initWithString:@"Test"];

// Will have a retain count of 2 here 
var = [[NSString alloc] initWithString:@"Test"] retain]

// Will have a retain count of 1 here, but will be released later on automatically
var = [[NSString alloc] initWithString:@"Test"] autorelease];

// Will have a retain count of 0 here, and will be released before it reaches the variable!
var = [[NSString alloc] initWithString:@"Test"] release];

その命名規則を持たないメソッドは、自動解放されたオブジェクトを返すことを示唆しています。開発者は、オブジェクトをより長く維持するために、明示的に何かを言う必要があります。

// Will have a retain count of 1 here, but will be released later on automatically
var = [NSString stringWithString:@"Test"];

// Will have a retain count of 1 here 
var = [[NSString alloc] initWithString:@"Test"] retain]

// Will have a retain count of 1 here, but will be released twice later on (Over-released!)
var = [[NSString alloc] initWithString:@"Test"] autorelease];

// Will have a retain count of 0 here, and will be released again later on (Over-released!)
var = [[NSString stringWithString:@"Test"] release];

ARC + MRC

ARC は、この不必要な解放と保持の必要性を取り除き、代わりに、割り当てられる変数の型に基づいてメモリ管理をどうするかを決定します。これは、メモリ管理モデルが変更されたという意味ではありません。それはまだすべてボンネットの下で保持および解放されています。そのため、これはあなたにどのように影響しますか? 簡潔にするために、この回答では弱い変数のみを考慮します。

弱い変数に割り当てても、オブジェクトの保持カウントは何もしません。説明する実際的な例を見てみましょう。

__weak UIView* monthView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 200.0)];

(実際には、ARC 性の背後で) これは保持されたオブジェクトを返しますが、弱い変数は保持カウントに影響を与えないため、コンパイラはメモリ リークを防ぐためにオブジェクトを解放する最も早い時点を見つけました。割り当て中!そのため、次のように変換され、エラーが発生します。

UIView* monthView = [[[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 200.0)] release];

さて、 に関してはmonthViewFromDateArray:、これは (その名前のために) コンパイラに、自動解放されたオブジェクト ( Documentation ) を返すことを示唆しています。コンパイラは、自動解放されたオブジェクトが後で実行ループで自動的に解放されることを認識しているため (自動解放プールが空になるとき)、release以前のように呼び出しを挿入しません。そのため、弱い変数への割り当ては問題ではありませんが、使用されているスコープ内でのみ有効です。

于 2012-12-05T18:58:10.977 に答える
1

メソッドがあるとしましょう

+(UIView*) create {
    return [[UIView alloc] init];
}

コンパイル時にこれに変換されます

+(UIView*) create {
    return [[[UIView alloc] init] autorelease];
}

今ここに:

UIView* __weak view;

//warning here
view = [[UIView alloc] init]; //1

view = [AppDelegate create];  //2

最初の行は次のように変換されます。

tempVar = [[UIView alloc] init];
storeWeak(tempVar, &view); //view = tempVar and marked as weak
[view release]; //view is nil after this because retain count == 0 (assignment to nil is done in release internally)

2 行目:

tempVar = [MyClass create];
[tempVar retainAutoreleasedReturnValue];
storeWeak(tempVar, &view); //view = tempVar and marked as weak
[release tempVar]; //view is not nil because tempVar is autoreleased later

次のようなコードがあるとします。

@autoreleasepool {
    view = [[UIView alloc] init];
    //view is nil here

    view = [AppDelegate create];
    //view equals to the return value
}
//view becomes nil here because [AppDelegate create] return value is released

コードの逆アセンブルを見ると、これらすべてを確認できます。

于 2012-12-05T19:23:09.923 に答える