2011-02-19 6 views
2

私は、比較的大きなデータセットを記述する素敵なオブジェクトを持っています。私はオブジェクトにいくつかのヘルパー機能を実装することにしました。明らかに私はセッターを書く方法を知らない

基本的に、NSString用の標準設定ツールを使用する代わりに、私自身の設定ツールを定義して、別のオブジェクトを同時に設定します。例えば

-(void) setNumber:(NSString *)number_in 
{ 
    number = [number_in copy]; 
    title = @"Invoice "; 
    title = [title stringByAppendingString:number]; 
} 

私は、特定の形式のプロパティとして「タイトル」が必要になります知っています。タイトルは番号に基づいているので、私は1つのパンチで番号とタイトルを設定するセッターを作成しました。 (タイトルはデフォルトの合成されたセッターを持っています...私は他のところでそれを定義しません)

何らかの理由で、メッセージが解放されたインスタンスエラーに送られています。このセッターを削除すると、コードは正常に動作します。

私のプロパティ定義はここにある:

@property (nonatomic, copy) NSString *number; 
@property (nonatomic, copy) NSString *title; 

私は無駄に、保持しようとしました。 Iセットアップのmallocスタックのログと、このログイン:最後に

Alloc: Block address: 0x06054520 length: 32 
Stack - pthread: 0xa003f540 number of frames: 30 
    0: 0x903ba1dc in malloc_zone_malloc 
    1: 0x102b80d in _CFRuntimeCreateInstance 
    2: 0x102d745 in __CFStringCreateImmutableFunnel3 
    3: 0x10824dd in _CFStringCreateWithBytesNoCopy 
    4: 0xae222e in -[NSPlaceholderString initWithCStringNoCopy:length:freeWhenDone:] 
    5: 0xaf9e8e in _NSNewStringByAppendingStrings 
    6: 0xaf9a76 in -[NSString stringByAppendingString:] 
    7: 0x112ba in -[Invoice setNumber:] at Invoice.m:25 
    8: 0x11901 in -[Invoice copyWithZone:] at Invoice.m:47 
    9: 0x107c7ca in -[NSObject(NSObject) copy] 
    10: 0x1117632 in -[NSArray initWithArray:range:copyItems:] 
    11: 0x107f833 in -[NSArray initWithArray:copyItems:] 
    12: 0x5595 in -[InvoicesTableViewController wrapper:didRetrieveData:] at InvoicesTableViewController.m:96 
    13: 0x4037 in -[Wrapper connectionDidFinishLoading:] at Wrapper.m:288 
    14: 0xb17172 in -[NSURLConnection(NSURLConnectionReallyInternal) sendDidFinishLoading] 
    15: 0xb170cb in _NSURLConnectionDidFinishLoading 
    16: 0x18ca606 in _ZN19URLConnectionClient23_clientDidFinishLoadingEPNS_26ClientConnectionEventQueueE 
    17: 0x1995821 in _ZN19URLConnectionClient26ClientConnectionEventQueue33processAllEventsAndConsumePayloadEP20XConnectionEventInfoI12XClientEvent18XClientEventParamsEl 
    18: 0x18c0e3c in _ZN19URLConnectionClient13processEventsEv 
    19: 0x18c0cb7 in _ZN17MultiplexerSource7performEv 
    20: 0x10fd01f in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ 
    21: 0x105b28b in __CFRunLoopDoSources0 
    22: 0x105a786 in __CFRunLoopRun 
    23: 0x105a240 in CFRunLoopRunSpecific 
    24: 0x105a161 in CFRunLoopRunInMode 
    25: 0x1c29268 in GSEventRunModal 
    26: 0x1c2932d in GSEventRun 
    27: 0x39542e in UIApplicationMain 
    28: 0x2199 in main at main.m:14 
    29: 0x2115 in start 

を、私はこのエラーを取得しておいてください。

-[CFString release]: message sent to deallocated instance 0x4b5aee0 

感謝万人を事前に:)

答えて

7

使用self.titleあなたに合成を起動します古い値のnumberを解放します。

- (void)setNumber:(NSString *)number_in 
{ 
    [number release]; 
    number = [number_in copy]; 
    self.title = [NSString stringWithFormat:@"Invoice %@", number]; 
} 
+0

私はあなたを愛していると思います。 (6分で承諾します) – clifgriffin

+0

それは良いです:) – fabian789

+0

または[タイトルのリリース]と[タイトル= [[NSString stringWithFormat:@ "請求書%@"、番号]保持] 'を書くことができます私はそれがすべきだと思うようにタイトルプロパティは読み取り専用です。 – tia

5

title自動解放なっているとnumberは、プログラムに漏れています。完全なセッターを作成するには、渡されたオブジェクトを最初にコピーしてからリリースする必要があります。

-(void) setNumber:(NSString *)number_in { 
    if (number == number_in) { 
     return; 
    } 

    NSString *oldValue = number; 
    number = [number_in copy]; 
    [oldValue release]; 

    self.title = [title stringByAppendingString:number]; 
} 

不変オブジェクトにcopyを呼び出すと、代わりに新しいコピーを作成するためのバックと同じオブジェクトを返す可能性があるため、最初にコピーしてから解除するための理由があります。したがって、setNumberが同じオブジェクトで2回呼び出され、numberが最初にリリースされた場合は無効になり、次に無効なオブジェクトでcopyを呼び出すと問題が発生する可能性があります。

ifチェックは最適化のステップです。必要に応じて削除することができます。

また、articleにカスタムセッターの書き込みについてチェックアウトすることもできます。

@tiaと@Markが投稿したように、titleが常にnumberの値に依存する場合、titleはreadonlyプロパティでなければなりません。 nil number_inが渡されたとき

- (void) setNumber:(NSString *)number_in { 
    if (number == number_in) { 
     return; 
    } 

    NSString *oldNumber = number; 
    number = [number_in copy]; 
    [oldNumber release]; 

    NSString *oldTitle = title; 
    title = [title stringByAppendingString:number]; 
    [oldTitle release]; 
} 

追加のチェックが必要になることがあり、次のようになりnilstringByAppendingStringに渡されたときのように変更setNumberはその後、NSInvalidArgumentExceptionを上昇させることがあります。だからここにチェックを入れてこのセッターの最終版を出します。

- (void) setNumber:(NSString *)number_in { 
    if (number == number_in) { 
     return; 
    } 

    NSString *oldNumber = number; 
    number = [number_in copy]; 
    [oldNumber release]; 

    if (number) { 
     NSString *oldTitle = title; 
     title = [title stringByAppendingString:number]; 
     [oldTitle release]; 
    } 
} 
+0

+1私は今までコピー操作中に古い値を保持する理由を理解できませんでした。ありがとう! –

+0

うわー。ありがとうございました。とても役に立ちました。 – clifgriffin

関連する問題