MST

星途 面试题库

面试题:Objective-C中关联对象的基本原理与使用场景

请简述Objective-C运行时中关联对象的基本原理,并举例说明在哪些场景下会使用关联对象技术。
10.9万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

关联对象基本原理

在Objective-C运行时中,关联对象是通过objc_setAssociatedObjectobjc_getAssociatedObjectobjc_removeAssociatedObjects这几个函数来实现的。

每个对象都有一个AssociationsManager,它内部管理着一个AssociationsHashMap。当通过objc_setAssociatedObject函数为对象设置关联对象时,会将源对象(设置关联对象的对象)、关联对象的键(可以是NSString等类型)以及关联对象的值包装成一个ObjectAssociation结构体,存储在AssociationsHashMap中。

当通过objc_getAssociatedObject获取关联对象时,会从AssociationsHashMap中根据源对象和键找到对应的ObjectAssociation结构体,从而取出关联对象的值。objc_removeAssociatedObjects则是将AssociationsHashMap中与源对象相关的所有关联对象移除。

使用场景举例

  1. 为类别(Category)添加属性:在Objective-C中,类别无法直接声明属性。通过关联对象技术,可以为类别添加“属性”。例如,为UIButton类别添加一个NSString类型的identifier属性,用于标识按钮的特定用途。
@interface UIButton (Identifier)
@property (nonatomic, strong) NSString *identifier;
@end

@implementation UIButton (Identifier)
- (void)setIdentifier:(NSString *)identifier {
    objc_setAssociatedObject(self, @selector(identifier), identifier, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSString *)identifier {
    return objc_getAssociatedObject(self, @selector(identifier));
}
@end
  1. 为代理模式提供补充信息:在代理模式中,有时候代理对象需要额外的信息来处理委托事件。例如,在一个图片下载的代理回调中,通过关联对象为下载任务对应的视图控制器存储一些额外的配置信息,如图片的显示尺寸等。
@interface ImageDownloader : NSObject
@property (nonatomic, weak) id<ImageDownloaderDelegate> delegate;
@end

@implementation ImageDownloader
- (void)downloadImageWithURL:(NSURL *)url {
    // 下载逻辑
    // 下载完成后调用代理方法,并可以通过关联对象传递额外信息
    id<ImageDownloaderDelegate> delegate = self.delegate;
    if ([delegate respondsToSelector:@selector(imageDownloaded:withInfo:)]) {
        NSDictionary *info = objc_getAssociatedObject(self, @selector(downloadInfo));
        [delegate imageDownloaded:image withInfo:info];
    }
}
@end
  1. 实现对象间的松散耦合关系:当两个对象之间需要传递数据,但又不想建立紧密的继承或组合关系时,可以使用关联对象。比如在一个复杂的视图层级中,一个子视图可能需要根据其所在父视图的一些特定配置来调整自身行为,通过关联对象可以在不直接引用父视图特定属性的情况下传递这些配置信息。