ios - 我可以通过调用另一个方法来执行设置的方式来实现属性 setter 吗?

标签 ios objective-c

考虑以下 setter :

- (void)setWinterStatus:(NSString *)status
{
    NSLog(@"Variable update called");
    if (_status != status)
    {
        [_status release];
        _status = [status retain];
        NSLog(@"Variable actually updated");
    }
}

- (void)setCharacterState:(EnumCharacterState)state
{
    NSLog(@"Variable update called");
    if (_state != state)
    {
        _state = state;
        NSLog(@"Variable actually updated");
    }
}

请注意,这些方法是相似的 - 它记录一条通用消息,检查它是否真的在改变,影响改变,如果改变了就记录下来。如果我有足够多的这样的方法,我可能想写一个包装器,这样我就可以简单地写:

- (void)setCharacterState:(EnumCharacterState)state
{
    [setValue:@(state) forSelector:@selector(state)];
}

但我不确定这是否可行。我不能使用 KVO,因为它似乎默认添加的 KVO 代码实际上调用了 setter,所以这样做会导致无休止的递归。我不知道如何从@selector(state) 获取instance 变量,也不知道它是否需要release/retain。有什么办法吗?

请注意:对象类型的基类必须保留为NSObject;我不能使用 NSManagedObject 作为基础来处理我自己的 KVO。

编辑:

所以显然有一种使用运行时 c 函数的方法(参见已接受的答案);似乎需要一些时间才能正确,但在此期间我找到了另一个解决方案。我将自己注册为所有我想要“包装”的方法的观察者,观察 NSKeyValueObservingOptionNewNSKeyValueObservingOptionOldNSKeyValueObservingOptionPrior。然后在先前的处理程序中,我 NSLog(@"Variable update called"),在更新处理程序中,我 NSLog(@"Variable actually updated")。这似乎效果很好:)

最佳答案

简答:是的,但不要。

长答案:

假设您出于教育原因想要这样做(而不是仅仅让编译器为您创建 setter,这是最近编译器中的默认设置),这是可能的,但它很重要。

您已经注意到一个区别——是否需要保留/释放(假设 MRC)——但还有更多区别。例如,考虑简单的行:

_state = state;

它有什么作用?复制一个字节?两个字节?八个字节?代码在不同的 setter 中可能看起来相同,但它编译为不同的机器代码。

然后要考虑属性上的复制和弱属性......

还在考虑这样做吗?

您需要熟悉void ** 的含义,通过指针复制可变长度的数据等。然后看看object_setInstanceVariableproperty_getAttributes 等 - 这些都是 C 函数,您可以在 Objective-C Runtime Reference 中找到它们.

从中您会发现您需要了解 type encodings (这将帮助您了解要复制多少字节),以及更多...

玩得开心!

HTH

关于ios - 我可以通过调用另一个方法来执行设置的方式来实现属性 setter 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28294838/

相关文章:

ios - 显示多个 map 的 SKMaps

iphone - 如果文件已经存在并且您尝试写入它会发生什么?

objective-c - UIScrollView 内的 UIView 未获取触摸事件

objective-c - 从应用程序委托(delegate)在应用程序窗口上添加标签

ios - 如何修复用于 Apple 应用提交的 setAllowsAnyHTTPSCertificate 私有(private) api?

ios - 在后台处理位置数据

ios - 如何在 iOS 中添加序号缩写格式 "th", "st"

android - 在多个平台上运行一个 Appium 测试

ios - 如何使用 Objective-C 从 Parse for iOS 中的二级指针检索值

iphone - 在 iphone 谷歌阅读器应用程序中将项目标记为已读/未读