1

ここで行われているプロセスを明確にしたいと思っています。

initメソッドが次のようになるUIButtonのサブクラスを作成しました。

- (id)initWithTitle:(NSString *)title frame:(CGRect)btnFrame {
    self = [UIButton buttonWithType:UIButtonTypeCustom];
    [self setTitle:title forState:UIControlStateNormal];
    self.frame = btnFrame;
    return self;
}

ビューコントローラで、これらのボタンの1つを作成し、それをサブビューとして追加しています。

myButton = [[CustomButton alloc] initWithTitle:@"Title" frame:someFrame];
[self.view addSubview:myButton];

ビューコントローラのdeallocメソッドでは、ボタンの保持カウントをログに記録します。

- (void)dealloc {
    NSLog(@"RC: %d", [myButton retainCount]); //RC = 2
    [super dealloc];
    NSLog(@"RC: %d", [myButton retainCount]); //RC = 1
}

私の理解では、myButtonは、を使用して呼び出したとしても、実際には保持されませんalloc。これは、サブクラスで(を使用して)自動解放ボタンを作成したためbuttonWithType:です。

で、これは、deallocが呼び出されると、スーパービューがボタンを解放し、その保持カウントが1に減少するdeallocことを意味しますか?ボタンはまだ自動リリースされていませんか?

または、[superdealloc]を呼び出した後にその保持カウントをゼロにする必要がありますか?

乾杯。

4

3 に答える 3

5

これは2つの答えに値します...1つは特定の質問に対するもので、もう1つはインスタンスが-init(これ)で置き換えられたときにメモリがどのように管理されるかに関するものです。

イニシャライザーは、Objective-Cのメモリ管理の世界では奇妙な鳥です。事実上、あなたは管理してselfいます。エントリ時に、self保持されます。終了時に、保持されたオブジェクト( -と同じオブジェクトである必要はありません)またはのいずれかを返すことが期待されます。self nil

だから、ダウンの標準的なイディオムを破る[[[Foo alloc] init] autorelease]

id x = [Foo alloc]; // allocates instance with RC +1
x = [x init]; // RC is preserved, but x may differ
[x autorelease]; // RC -1 (sometime in future)

すべての保持カウント[RC]はデルタとして表されることに注意してください。

したがって、このinit方法では、通常、保持カウントをまったく変更しませんself

ただし、他のオブジェクトを返す場合は、返す必要がありrelease self ます retain(その時点で割り当てられているか、以前に別の場所に割り当てられているか、たとえば、オブジェクトがキャッシュから取得されたとき)。

具体的には、この答えは過度に衒学的であるため、すべてが個々の表現に吹き飛ばされています。

- init {
    [self release];
    self = nil;
    id newObject = [SomeClass alloc];
    newObject = [newObject init];
    if (newObject) {
        self = newObject;
        ... initialize self here, if that is your fancy ...
    }
    return self;
}
于 2010-12-31T06:07:21.727 に答える
4

これは少し注意が必要です。私は私の答えを5つの部分にまとめました:

  1. init別のオブジェクトを返すカスタムメソッドを作成する
  2. 警告:不正なメモリアクセスに注意してください!
  3. ボタンの所有権を親ビューに適切に譲渡する方法
  4. 特定の質問に対する特定の回答
  5. 改善のための提案

パート1init :別のオブジェクトを返すカスタムメソッドの作成:

これは非常に特殊なケースの例です。つまり、返されるオブジェクトは、最初にメッセージが送信されたのと同じ「オブジェクト」で-initWithTitle:frame:はありません。

通常、プロセスは次のようになります。

instance = [Class alloc];
[instance init];
...
[instance release];

もちろん、alloc呼び出しとinit呼び出しは通常、1行のコードにグループ化されます。ここで注意すべき重要な点は、initの呼び出しを受け取る「オブジェクト」(この時点で割り当てられたメモリブロックにすぎない)がすでに割り当てられていることです。(例のように)別のオブジェクトを返す場合は、元のメモリブロックを解放する責任があります。

次のステップは、適切な保持カウントを持つ新しいオブジェクトを返すことです。ファクトリメソッド(+buttonWithType:)を使用しているため、結果のオブジェクトは自動解放されており、適切な保持カウントを設定するには、オブジェクトを保持する必要があります。

編集:適切な-initメソッドは、そのオブジェクトで他のことを行う前に、適切に初期化されたオブジェクトで機能していることを明示的にテストする必要があります。このテストは私の答えにはありませんでしたが、 bbumの答えには存在します。

initメソッドは次のようになります。

- (id)initWithTitle:(NSString *)title frame:(CGRect)btnFrame {
    [self release]; // discard the original "self"
    self = [UIButton buttonWithType:UIButtonTypeCustom];
    if (self == nil) { return nil; }
    [self retain]; // set the proper retain count
    [self setTitle:title forState:UIControlStateNormal];
    self.frame = btnFrame;
    return self;
}

パート2:警告:不正なメモリアクセスに注意してください!

のインスタンスを割り当ててから、のインスタンスにCustomButton置き換えると、UIButton非常に微妙なメモリエラーが発生する可能性があります。CustomButtonいくつかのivarがあるとしましょう:

@class CustomButton : UIButton
{
    int someVar;
    int someOtherVar;
}
...
@end;

これで、割り当てられたものをカスタムメソッドCustomButtonのインスタンスに置き換えると、を保持するには小さすぎるメモリブロックが返されますが、コードはこのコードブロックをフルサイズであるのように扱い続けます。 。ええとああ。UIButtoninit...CustomButtonCustomButton

たとえば、次のコードは非常に非常に悪いものになりました。

- (id)initWithTitle:(NSString *)title frame:(CGRect)btnFrame {
    [self release]; // discard the original "self"
    self = [UIButton buttonWithType:UIButtonTypeCustom];
    [self retain]; // set the proper retain count

    someOtherVar = 10; // danger, Will Robinson!

    return self;
}

パート3:ボタンの所有権を親ビューに適切に譲渡する方法:

ビューコントローラのメソッドについては、図のようにボタンを初期化した場合はdealloc呼び出す必要があります。[myButton release]これは、割り当て、保持、またはコピーするものはすべて解放する必要があるという規則に従うためです。この問題に対処するためのより良い方法は、コントローラーのビューにそのボタンの所有権を持たせることです(これは、ボタンをサブビューとして追加すると自動的に行われます)。

myButton = [[CustomButton alloc] initWithTitle:@"Title"
                                         frame:someFrame]; // RC = 1
[self.view addSubview:myButton];                           // RC = 2
[myButton release];                                        // RC = 1

これで、そのボタンをもう一度離すことを心配する必要はありません。ビューはそれを所有し、ビュー自体の割り当てが解除されたときに解放します。


パート4:特定の質問に対する特定の回答:

Q:私の理解では、allocを使用して呼び出しても、myButtonは実際には保持されません。これは、サブクラスで(buttonWithType :を使用して)自動解放ボタンを作成したためです。

正しい。

Q:deallocでは、deallocが呼び出されると、スーパービューがボタンを解放し、その保持カウントが1に減少することを意味しますか?ボタンはまだ自動リリースされていませんか?

また正しい。

Q:または、[superdealloc]を呼び出した後に保持カウントをゼロにする必要がありますか?

ある種:)の保持カウントは、ログに記録した時点でゼロに低下する場合と低下しない場合があります。自動解放されたオブジェクトは、現在の実行ループの自動解放プールに効果的に属しているため、保持カウントが1のままである可​​能性があります。さらに言えば、ビュー自体はまだリリースされていないウィンドウに属している可能性があります。あなたが本当に心配する必要がある唯一のことはあなた自身のメモリ管理のバランスをとることです。詳細については、 Appleのメモリ管理ガイドを参照してください。viewControllerの観点からは、ボタンを1回割り当てたので、ボタンを1回だけ離す必要があります。あなたの習慣になるとinit...方法では、物事は少しトリッキーになりますが、原則は同じです。メモリのブロックが割り当てられているため、解放する必要があり(パート1)、(パート2)initは保持カウントが1のオブジェクトを返す必要があります(後で適切に解放されるため)。


パート5:改善のための提案:

によって提供されるものと同じ精神で独自のファクトリメソッドを作成するだけで、カスタム初期化子の混乱のほとんどを回避できますUIButton

+ (id)buttonWithTitle:(NSString *)title frame:(CGRect)btnFrame {
    UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
    [button setTitle:title forState:UIControlStateNormal];
    button.frame = btnFrame;
    return button;
}

このアプローチでは、パート2で特定されているように、メモリアクセスエラーが発生する可能性があることに注意してください。

于 2010-12-31T05:36:42.470 に答える
1

初め:

保持カウントを呼び出さないでください

オブジェクトの絶対保持数はほとんど役に立たない。アプリケーションのメモリ管理について推論するためのより良い方法は常にあります。


次:

メソッドは、サブクラスのインスタンスではなく、のインスタンスinitWithTitle:frame:を割り当てて返します。UIButtonそれが必要な場合は、サブクラスはまったく必要ありません。

UIButtonのサブクラスのインスタンスが本当に必要な場合、それはさらに困難になります。クイックグーグル検索とドキュメントの読み取りは、UIButton実際にはサブクラス化されることを意図していないことを示しています。

私はちょうど試しました:

@interface FooButton:UIButton
@end
@implementation FooButton
@end

FooButton *f = [FooButton buttonWithType: UIButtonTypeDetailDisclosure];
NSLog(@"%@", f);

そしてそれは印刷しました:

<UIButton: 0x9d03fa0; frame = (0 0; 29 31); opaque = NO; layer = <CALayer: 0x9d040a0>>

UIButtonつまり、インスタンスを作成するために使用される唯一のメソッドは、を介して割り当てられませ[self class]。手動でインスタンスを初期化しようとする道をたどることもできますUIViewUIControl、それはおそらく多くの問題です。

あなたは何をしようとしているのですか?

于 2010-12-31T05:48:23.730 に答える