【问题标题】:User defined runtime attributes (IBInspectable) set after pre-defined attributes?在预定义属性之后设置用户定义的运行时属性(IBInspectable)?
【发布时间】:2017-01-12 15:05:36
【问题描述】:

我希望通过类别方法将新的IBInspectable 属性(计算属性)添加到UILabel。理想情况下,我希望在设置标签文本之后设置此属性(通过 setValue:forKey),因为此 IBInspectable 属性可能导致 UILabels 文本被更新,我们不希望 UILabel 中的文本稍后替换它。查看文档并没有提及在界面生成器中配置的属性的nib/storyboard 加载期间是否总是在用户定义的属性之前设置预定义的属性。

是否使用IBInspectable 或用户定义的运行时属性将自定义属性添加到 Interface Builder 中的对象,并保证在标准预定义对象属性/属性之后设置?

【问题讨论】:

  • 如果您是以编程方式设置标签的文本(如在 viewDidLoad 中),或者您的意思是在 IB 中设置,您能更清楚吗?
  • 抱歉都是通过IB设置的

标签: ios storyboard interface-builder nib


【解决方案1】:

如果您使用 IBInspectable 计算机变量创建扩展,当在 Interface Builder 中设置两个值时,放置在 Interface Builder 中该自定义字段中的值将覆盖标签文本字段中的值,即使它不会以这种方式预览在界面生成器中。

extension UILabel {

    @IBInspectable var value: String? {
        get {
            return text
        }

        set {
            text = newValue
            setNeedsDisplay()
        }
    }

}

【讨论】:

  • 感谢您的回答。我已经实现了类似的扩展并在不同版本的 iOS 上进行了测试,我注意到了相同的行为。然而;我希望它被记录在某个地方,这样我就可以在生产代码中完全安全地使用它。
【解决方案2】:

以下实验得出结论,原生文本属性设置在类别属性之前,因此该值可以安全地被类别设置器覆盖。

一个标签类别:

//  UILabel+Thingy.h

#import <UIKit/UIKit.h>

@interface UILabel (Thingy)

@property (nonatomic, strong) IBInspectable NSString *thingy;

@end

//  UILabel+UILabel_Thingy.m

#import "UILabel+Thingy.h"
#import <objc/runtime.h>

@implementation UILabel (Thingy)

- (NSString *)thingy {
    return objc_getAssociatedObject(self, @selector(thingy));
}

- (void)setThingy:(NSString *)thingy {
    NSLog(@"setting thingy to '%@', my text is currently '%@'", thingy, self.text);
    objc_setAssociatedObject(self, @selector(thingy), thingy, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

@end

在 IB 中,设置可检查的类别属性和文本属性......

包含视图控制器中的一个小工具:

- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"didLoad text is '%@' and thingy is '%@'", self.label.text, self.label.thingy);
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    NSLog(@"willAppear text is '%@' and thingy is '%@'", self.label.text, self.label.thingy);
}

运行它,NSLog 输出表明在从 nib 唤醒期间,本地属性在调用类别属性设置器时设置...

...[794:41622] 将thingy 设置为'thingy value',我的文本当前是'text value'

...[794:41622] didload text 是 'text value' 而 thingy 是 'thingy value'

...[794:41622] 会出现 text is 'text value' 而 thingy 是 'thingy value'

在类别属性设置器中设置标签的 text 属性将(并且确实,我测试过)导致 text 属性被覆盖到 thingy 属性,因为 text 属性首先被初始化。

当呈现为 XML 时,可以在 XIB 文件中看到更多证据...

<label opaque="NO" (... all the native properties) text="text value" (...) id="XAM-6h-4fn">
    <rect key="frame" x="274" y="147" width="278" height="34"/>

    (... and so on)

    <userDefinedRuntimeAttributes>
        <userDefinedRuntimeAttribute type="string" keyPath="thingy" value="thingy value"/>
    </userDefinedRuntimeAttributes>
</label>

... 这与通过 pre-order 遍历被实例化和初始化的视图一致,从而在(子标签)userDefinedRuntimeAttributes 之前设置(父标签)标签属性。

【讨论】:

  • 感谢您的回复。在对不同版本的 iOS 进行测试期间,我注意到了相同的行为。然而;我希望它被记录在某个地方,这样我就可以在生产代码中完全安全地使用它。
  • 似乎没有明确涵盖人们希望在文档中看到它的地方。但是所证明的确定性行为比文档更好,对吧?只要它使用 100% 的公共 API,就可以认为该行为对于您的应用程序是永久的,就像 SDK 的任何部分一样。
  • 我猜想在未来的 iOS 版本中会担心订单发生变化而没有任何明显的 API 变化。
  • 我想我会继续使用 objc_setAssociatedObject。谢谢
  • 当然,这取决于你,但应用程序是静态编译的。它附带的框架可以改变,但如果没有开发人员使用更新的东西重建,应用程序就不会改变。
猜你喜欢
  • 1970-01-01
  • 2014-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-30
  • 2020-03-26
相关资源
最近更新 更多