我只想像这样向UIView
添加一个属性,
#import "UIView+Extension.h"
#import <objc/runtime.h>
@implementation UIView (Extension)
- (void)setMaxWidth:(CGFloat)maxWidth {
objc_setAssociatedObject(self, @selector(maxWidth), @(maxWidth), OBJC_ASSOCIATION_ASSIGN);
}
- (CGFloat)maxWidth {
return [objc_getAssociatedObject(self, _cmd) doubleValue];
}
@end
但是有时候有用,有时候崩溃了。
我在XCode中获得的崩溃信息是此行return [objc_getAssociatedObject(self, _cmd) doubleValue];
。
我在Bugly遇到的崩溃是这个NSInvalidArgumentException -[_UILabelStringContent doubleValue]: unrecognized selector sent to instance 0x2804fb280
。
那么为什么会这样。我只是设置了float value
,但得到了_UILabelStringContent value
。
PS:我的项目使用的是Swift 5.0,但我只是使用Objective-C运行时添加额外的属性。
PS2:我在另一个Objective-C项目中使用了相同的代码,不会崩溃。
PS3:它并不总是崩溃。
PS4:我在UIView
和BaseLabel
中使用了此属性,但仅在BaseLabel
中崩溃了。
PS5:我用它来更新框架,像这样在BaseLabel
中用它。
override func sizeToFit() {
super.sizeToFit()
if self.maxWidth > 0 {
if numberOfLines != 1 {
let size = self.sizeThatFits(CGSize(width: maxWidth, height: CGFloat.greatestFiniteMagnitude))
self.size = size
} else {
if self.size.width > maxWidth {
self.size.width = maxWidth
}
}
}
}
PS6:是_cmd
中的objc_getAssociatedObject(self, _cmd)
的崩溃呼叫吗??
答案 0 :(得分:0)
在- (void)setMaxWidth:(CGFloat)maxWidth
内,您正在创建 NSNumber
的后备对象,该对象保留CGFloat
缩短的语法所隐含的@(maxWidth)
的值。由于NSNumber
是NSObject
的子类,因此您不应该使用OBJC_ASSOCIATION_ASSIGN
,它对于具有ARC处理的引用计数的类型无效(对于诸如Integer
的值类型有效)。您应该改用OBJC_ASSOCIATION_RETAIN
。
将您的代码更新为
- (void)setMaxWidth:(CGFloat)maxWidth {
objc_setAssociatedObject(self, @selector(maxWidth), @(maxWidth), OBJC_ASSOCIATION_RETAIN);
}
关于PS6部分_cmd
是给定Objective-C方法主体中的选择器名称(内部表示为char*
)。对于每个通过选择器的方法调用,它作为“隐藏”参数(从obj-c语法角度来看)传递。除非方法调用的格式不正确,否则访问它可能不会导致崩溃。