【问题标题】:`objc_setAssociatedObject` and `objc_getAssociatedObject` isn't match`objc_setAssociatedObject` 和 `objc_getAssociatedObject` 不匹配
【发布时间】:2019-11-24 02:19:41
【问题描述】:

我只想像这样给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:我在UIViewBaseLabel 中使用了这个属性,但只在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:_cmdobjc_getAssociatedObject(self, _cmd) 中的崩溃调用??

【问题讨论】:

  • 看起来关联的对象正在被释放,并且内存被其他对象重用了。尝试启用 NSZombie 调试以确认。

标签: ios objective-c swift crash


【解决方案1】:

- (void)setMaxWidth:(CGFloat)maxWidth 内部,您正在创建 NSNumber 支持对象,该对象包含@(maxWidth) 缩短语法所暗示的CGFloat 值。由于NSNumberNSObject 的子类,因此您不应该使用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 语法的角度来看)传递。除非方法调用格式不正确,否则访问它不会导致崩溃。

【讨论】:

    猜你喜欢
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 2021-09-01
    • 2013-01-14
    • 2019-01-25
    • 1970-01-01
    • 2012-12-05
    • 2011-12-21
    相关资源
    最近更新 更多