如何在 Swift 中翻译 @synthesize 协议变量?

Posted

技术标签:

【中文标题】如何在 Swift 中翻译 @synthesize 协议变量?【英文标题】:How do you translate a @synthesize protocol variable in Swift? 【发布时间】:2020-09-08 13:58:32 【问题描述】:

我必须将一些文件从 Objective-C 转换为 Swift。问题是我真的对被称为相同的协议和类以及我不知道如何初始化或如何转换为 Swift 的 @synthetize 协议变量感到困惑。我会尝试做一个简单的方案。

// Protocols.h
ProtocolA 
 - functionA


ProtocolB 
 - variableNameB : ProtocolA // Can a variable be of type protocol? shouldn't it be of type class and that class is the one that follows the protocol?
 - functionB

------------------------

// Class1.m
Class1: ProtocolB 
// This is what I don't understand at all, how is initiating itself? There are not initialisers for Protocols.
@synthesize variableNameB = _variableNameB 


我得到的错误

如果我尝试只写 var variableNameB: ProtocolA 而不给出任何值,我将在 Class1 的 init 方法中得到这个:

属性“self.variableNameB”未在隐式生成时初始化 super.init 调用

如果我尝试在 Class1 init 中初始化它,执行 self.variableNameB = ProtocolA() 我得到:

无法构造ProtocolA,因为它没有可访问的 初始化器

如果我尝试将 variableNameB 设为可选,因此我不会强制对其进行初始化,我会得到:

getter 提供的 Objective-C 方法 'variableNameB' 'variableNameB' 与可选要求 getter 冲突 协议ProtocolB中的'variableNameB'

setter 提供的 Objective-C 方法 'setVariableNameB:' variableNameB 与可选要求设置器冲突 协议ProtocolB中的'variableNameB'


额外上下文、OBJECTIVE-C 和 SWIFT 的所有文件

TermsAndConditionsReader.h

@class UserAccountManager;
@class TermsAndConditionsManager;
@protocol TermsAndConditionsManagerObserver;

NS_ASSUME_NONNULL_BEGIN

@interface TermsAndConditionsReader : GenericInteractor <TermsAndConditionsReader>

INTERACTOR_INIT_UNAVAILABLE;

- (instancetype)initWithUserAccountManager:(UserAccountManager*)userAccountManager
                 termsAndConditionsManager:(TermsAndConditionsManager*)termsAndConditionsManager
                                     appId:(NSUInteger)appId NS_DESIGNATED_INITIALIZER;


@property (nonatomic, strong, readonly) UserAccountManager* userAccountManager;
@property (nonatomic, strong, readonly) TermsAndConditionsManager* termsAndConditionsManager;

@end

NS_ASSUME_NONNULL_END

TermsAndConditionsReader.m

@interface TermsAndConditionsReader () <TermsAndConditionsManagerObserver>

  @property (nonatomic, assign) NSUInteger appId;

@end

@implementation TermsAndConditionsReader
  @synthesize listener = _listener;

- (instancetype)initWithUserAccountManager:(UserAccountManager*)userAccountManager
                 termsAndConditionsManager:(TermsAndConditionsManager*)termsAndConditionsManager
                                     appId:(NSUInteger)appId 
    self = [super init];

    if (self) 
        _userAccountManager = userAccountManager;
        _termsAndConditionsManager = termsAndConditionsManager;
        [termsAndConditionsManager addTermsAndConditionsManagerObserverWithObserver:self];
        _appId = appId;
    

    return self;


- (BOOL)areTermsAndConditionsAccepted 
    id<UserAccount> userAccount = self.userAccountManager.userAccount;
    return [userAccount hasAcceptedTermsAndConditionsForApp:self.appId];


#pragma mark - TermsAndConditionsManagerObserver

- (void)termsAndConditionsManagerUserNeedsToAcceptNewTermsWithSender:(TermsAndConditionsManager * _Nonnull)sender 
    [self.listener termsAndConditionsReaderNewTermsAndConditionsHasToBeAccepted:self];


@end

TermsAndConditionsReader.swift --> 这可能是错误的,这是我尝试转换的方式

@objc public class TermsAndConditionsReader: GenericInteractor, TermsAndConditionsReaderProtocol, TermsAndConditionsManagerObserver 

let userAccountManager: UserAccountManager
let termsAndConditionsManager: TermsAndConditionsManager
let appId: UInt
public var listener: AnyObject & TermsAndConditionsListener

@objc public init(userAccountManager: UserAccountManager, termsAndConditionsManager: TermsAndConditionsManager, appId: UInt) 
    self.appId = appId
    self.userAccountManager = userAccountManager
    self.termsAndConditionsManager = termsAndConditionsManager
    termsAndConditionsManager.addTermsAndConditionsManagerObserver(observer: self) // -> It complains here because I am calling self before having initialised listener


// MARK: - TermsAndConditionsReaderProtocol

@objc public func areTermsAndConditionsAccepted() -> Bool 
    return self.userAccountManager.userAccount?.hasAcceptedTermsAndConditions(forApp: self.appId) ?? false


// MARK: - TermsAndConditionsManagerObserver

@objc public func termsAndConditionsManagerUserNeedsToAcceptNewTerms(sender: TermsAndConditionsManager) 
    // call listener here:


InteractorsTermsAndConditions.h

@protocol TermsAndConditionsListener <NSObject>

- (void)termsAndConditionsReaderNewTermsAndConditionsHasToBeAccepted:(id<TermsAndConditionsReader>)sender;

@end


@protocol TermsAndConditionsReader <NSObject>

@property (nonatomic, weak, nullable) id<TermsAndConditionsListener> listener;

- (BOOL)areTermsAndConditionsAccepted;

@end

InteractorsTermsAndConditions.swift -> 我是这样翻译的

@objc public protocol TermsAndConditionsListener 
    @objc func termsAndConditionsReaderNewTermsAndConditionsHasToBeAccepted(sender: TermsAndConditionsReaderProtocol)




@objc public protocol TermsAndConditionsReaderProtocol 

    @objc var listener: AnyObject &  TermsAndConditionsListener  get set 
    @objc func areTermsAndConditionsAccepted() -> Bool


【问题讨论】:

【参考方案1】:

您不能在 Class1 实现中使用 ProtocolA 作为类型;您需要声明另一个 Class2: ProtocolA 并将其用作您的 variableNameB

在您的代码上下文中,您需要声明

// rename your listener protocol
protocol TermsAndConditionsListenerProtocol 
    // whatever requirements


// implement a concrete type that conforms to this protocol
class TermsAndConditionsListener: TermsAndConditionsListenerProtocol 
    // implement requirements 
    // as well as any init you need
    init(hello: String)  /* ... */ 


// adjust your reader protocol
protocol TermsAndConditionsReaderProtocol 
    var listener: TermsAndConditionsListenerProtocol  get set 
    func areTermsAndConditionsAccepted() -> Bool


// implement a concrete reader that conforms to reader protocol
class TermsAndConditionsReader: TermsAndConditionsReaderProtocol 
    // here you use a concrete type that conforms to the listener protocol
    var listener: TermsAndConditionsListener = .init(hello: "world")
    
    // + other requirements

【讨论】:

是否可以像遵循此协议的任何类一样声明和初始化变量?我真的需要创建一个特定的类吗?在 Objective-C 中并没有这样做,所以如果我在我的 Swift 转换中这样做,我可能会破坏代码中的一些抽象层 您的 ObjC 代码库不包含任何符合您的侦听器协议的类? ? 你怎么知道当你打电话给listener. termsAndConditionsReaderNewTermsAndConditionsHasToBeAccepted() 时会发生什么? 有一个类,叫做RouteEventHandler,它符合很多不同的Listener协议。我无法在我的 TermsAndConditionsReader 类中初始化这个RouteEventHandler,因为它需要很多我无法访问的参数。 RouteEventHandler 也位于不同的项目模块中。

以上是关于如何在 Swift 中翻译 @synthesize 协议变量?的主要内容,如果未能解决你的问题,请参考以下文章

基于Xilinx的Synthesize

如何在 swift 2.0 中翻译我的硬编码字符串? [复制]

翻译: Swift 中的委托保留周期 如何在“纯”Swift(没有@objc)中进行弱协议引用

如何在 Swift 3 中从数据中提取 Int16

@dynamic 和 @synthesize 有啥区别?

@property 和@synthesize:为啥两者都有?