1
\$\begingroup\$

I am using one of the open-source Objective-C keychain wrappers to store data in iOS keychain. For test cases, I have created protocol as:

protocol KeychainProtocol {
    func deletePassword(forService service: String, account: String) -> Bool
    func setPassword(_ password: String, forService service: String, account: String) -> Bool
}

This is my keychain wrapper class:

@interface KeychainWrapper : NSObject

+ (BOOL)deletePasswordForService:(NSString *)serviceName account:(NSString *)account;
+ (BOOL)setPassword:(NSString *)password forService:(NSString *)serviceName account:(NSString *)account;

@end

I have written mock class KeychainProtocolMock which conforms to KeychainProtocol.
In test cases I am simply doing this:

class DatabaseInterfaceTests: XCTestCase {

    override func setUp() {
        super.setUp()
        KeychainController.shared.delegate = KeychainProtocolMock()
    }

    override func tearDown() {
        KeychainController.shared.delegate = nil
        super.tearDown()
    }

    func testPasswordsAfterWipeAllData() {
        //test functions which deals with keychain data 
    }  
}

This is my controller class:

class KeychainController: NSObject {

    static let shared = KeychainController()
    var delegate: KeychainProtocol?

    class func deletePassword(forService service: String, account: String) -> Bool {
        let delegate = KeychainController.shared.delegate
        return delegate != nil ? delegate!.deletePassword(forService: service, account: account) : KeychainWrapper.deletePassword(forService: service, account: account)
    }

    class func setPassword(_ password: String, forService service: String, account: String) -> Bool {
        let delegate = KeychainController.shared.delegate
        return delegate != nil ? delegate!.setPassword(password, forService: service, account: account) : KeychainWrapper.setPassword(password, forService: service, account: account)
    }
}

In my app code, whenever I need keychain data I am accessing it through controller class as:

let password = KeychainController.password(forService: DBPasswordService, account: DBPasswordAccount)

It is working absolutely fine, but still I have some doubt about my implementation ofKeychainController class. It looks messy!

Is there any better way to handle this situation where I can use class/static protocol methods in Swift and ask Objective-C keychain wrapper class to conform it?

\$\endgroup\$
  • \$\begingroup\$ Please see my answer to your previous question, apply what you've learned from the answer you've marked as accepted, and take another stab at this. \$\endgroup\$ – nhgrif Jan 28 '17 at 19:28
  • \$\begingroup\$ KeychainWrapper class has static methods only, so it can't conform to KeychainProtocol. This is my concern, I can't do it same like Userdefaults. \$\endgroup\$ – D4ttatraya Jan 28 '17 at 21:43
  • \$\begingroup\$ Just as an example, you could simply remove class from the KeychainController methods to get you moving in the right direction. \$\endgroup\$ – nhgrif Jan 28 '17 at 22:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.