ios - `objc_setAssociatedObject` 和 `objc_getAssociatedObject` 不匹配
问题描述
我只想添加一个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:我在 and 中使用了 this 属性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)
吗?
解决方案
在内部- (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
是给定目标 c 方法主体中的选择器名称(内部表示为char*
)。它通过选择器作为每个方法调用的“隐藏”参数(从 obj-c 语法的角度来看)传递。除非方法调用以某种方式格式错误,否则访问它不是崩溃的可能原因。
推荐阅读
- mysql - 如何通过laravel中的视图计算表中的用户数?
- c# - 如何覆盖现有 Excel 文件的工作表
- javascript - API 的 Javascript 效率
- javascript - Angular 7 - 创建具有角度样式的隔离范围的组件背后的机制是什么?
- reactjs - 通过包装组件控制 Flatpickr 日历视图的打开/关闭
- amazon-web-services - AWS SES 将其自定义模板存储在哪里,我们可以为这些 SES 模板提供跨区域副本吗
- json - JSON格式说明
- graphics - 编写Shader代码需要学习哪些东西?
- javascript - Javascript 自动计数 30 天并从表中删除数据
- anylogic - 为什么我使用 getRouteData() 和 getNumberOfTransporters() 的 transporterControl 方法错误?