I have to convert some files from objective-C into Swift. The problem is that I am really confused between protocols and classes that are called the same, and the @synthetize protocol variable that I don't know how to init or how to translate into Swift. I'll try to make a simple scheme.
// 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
}
ERRORS I GET
If I try to just write var variableNameB: ProtocolA without giving any value, I will get this in the Class1 init method:
Property 'self.variableNameB' not initialized at implicitly generated super.init call
If I try to initialise it inside the Class1 init doing self.variableNameB = ProtocolA() I get:
ProtocolA cannot be constructed because it has no accessible initializers
If I try to make variableNameB optional, so I am not force to initialize it, I get:
Objective-C method 'variableNameB' provided by getter for 'variableNameB' conflicts with optional requirement getter for 'variableNameB' in protocol ProtocolB
Objective-C method 'setVariableNameB:' provided by setter for variableNameB conflicts with optional requirement setter for 'variableNameB' in protocol ProtocolB
ALL FILES FOR EXTRA CONTEXT, 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 --> This is probably wrong, it's how I tried to convert it
@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 -> This is how I translated it
@objc public protocol TermsAndConditionsListener {
@objc func termsAndConditionsReaderNewTermsAndConditionsHasToBeAccepted(sender: TermsAndConditionsReaderProtocol)
}
@objc public protocol TermsAndConditionsReaderProtocol {
@objc var listener: AnyObject & TermsAndConditionsListener { get set }
@objc func areTermsAndConditionsAccepted() -> Bool
}
You cannot use
ProtocolAas a type in yourClass1implementation; you need to declare anotherClass2: ProtocolAand use that as yourvariableNameBIn the context of your code, you'd need to declare