显然我不知道如何编写 setter

发布于 2024-10-17 23:27:21 字数 2653 浏览 1 评论 0原文

我有一个很好的对象,它描述了一个相对较大的数据集。我决定在对象中实现一些辅助功能。

基本上,我没有使用 NSString 的标准 setter,而是定义自己的 setter 并同时设置另一个对象。

例如:

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

我知道我需要“标题”作为某种格式的属性。标题是基于数字的,所以我创建了一个设置器来一拳设置数字和标题。 (标题具有默认的合成设置器...我没有在其他地方定义它)

出于某种原因,我收到发送到已释放实例错误的消息。如果我删除这个设置器,代码就可以正常工作。

我的属性定义在这里:

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

我尝试过保留,但无济于事。我设置了 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

提前感谢一百万:)

I have a nice object that describes a relatively large data set. I decided to implement some helper functionality in the object.

Basically, instead of using the standard setter for a NSString, I define my own setter and set another object at the same time.

For example:

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

I know I will need "title" as a property in a certain format. Title is based on the number, so I created a setter to set number and title in one punch. (title has the default synthesized setter...I don't define it elsewhere)

For some reason, I'm getting the message sent to deallocated instance error. If I delete this setter, the code works fine.

My property definition is here:

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

I've tried retaining, to no avail. I setup malloc stack logging and logged this:

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

In the end, I keep getting this error:

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

Thanks a million in advance :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

眼波传意 2024-10-24 23:27:21

使用 self.title 调用合成的 setter 并释放 number 的旧值。

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

Use self.title to invoke your synthesized setter as well as release the old value for number.

- (void)setNumber:(NSString *)number_in
{
    [number release];
    number = [number_in copy];
    self.title = [NSString stringWithFormat:@"Invoice %@", number];
}
别在捏我脸啦 2024-10-24 23:27:21

title 正在自动释放,number 正在程序中泄漏。要编写完整的 setter,您应该首先复制传入的对象,然后进行释放。

-(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 两次,并且 number 首先被释放,则它会变得无效,然后在该无效对象上调用 copy可能会导致问题。

if 检查是一个优化步骤,如果需要,您可以删除它。

另外,您可能还想查看这篇文章 关于编写自定义设置器。

正如 @tia 和 @Mark 所发布的,如果 title 始终依赖于 number 的值,那么 title 应该是一个 readonly 属性。修改后的 setNumber 可能看起来像这样,

- (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];
}

当传递 nil number_in 时,可能需要进行额外的检查,就像当将 nil 传递给 < code>stringByAppendingString,会引发 NSInvalidArgumentException。这是带有该检查的 setter 的最终版本,

- (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];
    }
}

title is getting autoreleased and number is leaking in the program. To write a thorough setter, you should first copy the passed in object, and then do a release.

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

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

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

The reason for copying first and then releasing is because calling copy on an immutable object may return the same object back instead of creating a new copy. So if setNumber is called twice with the same object, and number was released first, it becomes invalid, then calling copy on that invalid object next could cause issues.

The if check is an optimization step, which you could remove if you wanted.

Also, you may want to checkout this article on writing custom setters.

As @tia and @Mark have posted, if title is always dependent on the value of number, then title should be a readonly property. The modified setNumber may then look like,

- (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];
}

Additional checks may be needed for when a nil number_in is passed, as when a nil is passed to stringByAppendingString, a NSInvalidArgumentException is raised. So here goes the final version of this setter with that check,

- (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];
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文