これは少し注意が必要です。私は私の答えを5つの部分にまとめました:
init
別のオブジェクトを返すカスタムメソッドを作成する
- 警告:不正なメモリアクセスに注意してください!
- ボタンの所有権を親ビューに適切に譲渡する方法
- 特定の質問に対する特定の回答
- 改善のための提案
パート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
のインスタンスに置き換えると、を保持するには小さすぎるメモリブロックが返されますが、コードはこのコードブロックをフルサイズであるかのように扱い続けます。 。ええとああ。UIButton
init...
CustomButton
CustomButton
たとえば、次のコードは非常に非常に悪いものになりました。
- (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で特定されているように、メモリアクセスエラーが発生する可能性があることに注意してください。