You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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中的实现逻辑完全对齐。

需要注意两个细节:

  1. 如果外部传入了仅符合父协议但不符合子类协议的实例,_output会被设为nil——这是类型安全的保障,但如果业务逻辑不允许这种情况,可以在setter里添加断言或日志,方便调试排查问题。
  2. 保持弱引用的内存管理逻辑不变,避免出现循环引用的问题。

内容的提问来源于stack exchange,提问作者ppalancica

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 10:44:52