Swift遵循Objective-C协议时,弱属性子类类型兼容实现是否正确?
问题:Swift中如何在遵循Objective-C协议的同时将属性实际类型改为子类协议?
我原本有一个遵循Objective-C协议的Swift属性:
@objc public weak var output: ELGameFramePresenterOutput?
基于架构要求,需要把这个属性的实际类型改为ELPracticeGameFlowPresenterOutput(它是ELGameFramePresenterOutput的子类协议)。但因为var output: ELGameFramePresenterOutput?来自Objective-C协议,Swift里不能直接把属性类型替换成子类协议(Objective-C里可以这么做)。
请问下面这种写法能否在遵循协议的同时,让属性实际返回子类协议类型?
private weak var _output: ELPracticeGameFlowPresenterOutput? @objc public weak var output: ELGameFramePresenterOutput? { get { return _output } set { _output = newValue as? ELPracticeGameFlowPresenterOutput } }
补充信息
ELGameFramePresenterIO.m
@protocol ELGameFramePresenterInput <NSObject> - (NSString *)identifier; - (void)setView:(id<ELGameFrameViewInput>)view; @property(nonatomic, weak) id<ELGameFramePresenterDelegate> delegate; @property(nonatomic, weak) id<ELGameFramePresenterOutput> output; @property(nonatomic) ELGameInfoViewController *gameInfoController; @end @protocol ELGameFramePresenterOutput <NSObject> - (void)requestGameId:(NSInteger)gameId; - (void)requestNextSubcategory; - (void)gameFramePresenter:(id<ELGameFramePresenterInput>)presenter didCompleteGame:(ELStudyGameInfo *)game; - (id<ELGameCompletionPresenter>)completionPresenterForGameFramePresenter:(id<ELGameFramePresenterInput>)presenter; @end
ELPracticeGameFlowPresenterIO.swift
@objc public protocol ELPracticeGameFlowPresenterOutput: ELGameFramePresenterOutput {}
原本我有一个Objective-C类ELPracticeGameFlowPresenter,它遵循ELPracticeGameFlowPresenterInput(继承自ELGameFramePresenterInput)协议,协议里定义的属性是:
@property(nonatomic, weak) id<ELGameFramePresenterOutput> output;
但实际实现时,我把这个属性的类型改成了:
@property(nonatomic, weak) id<ELPracticeGameFlowPresenterOutput> output;
在Objective-C里这种写法是合法的,但Swift里会提示不符合协议要求。我希望在Swift里实现同样的功能,最终决定采用前面提到的写法。
解答
这种写法是完全可行的,能完美匹配你想要的Objective-C实现逻辑:
- 满足协议合规性:公开的
output属性类型严格对应Objective-C协议的定义,Swift编译器会认定你符合协议要求,不会抛出合规性错误。 - 实现类型约束:内部通过私有
_output变量存储ELPracticeGameFlowPresenterOutput类型实例,setter里的as?转换确保只有符合子类协议的实例能被留存,保证了内部使用的类型安全。 - 功能完全一致:getter返回
_output并对外展示为父协议类型,外部调用时只能访问父协议的方法,而内部可以安全地使用子类协议的所有能力,和你在Objective-C中的实现逻辑完全对齐。
需要注意两个细节:
- 如果外部传入了仅符合父协议但不符合子类协议的实例,
_output会被设为nil——这是类型安全的保障,但如果业务逻辑不允许这种情况,可以在setter里添加断言或日志,方便调试排查问题。 - 保持弱引用的内存管理逻辑不变,避免出现循环引用的问题。
内容的提问来源于stack exchange,提问作者ppalancica
相关产品推荐
相关产品推荐

