简体   繁体   中英

Category for obj-c class derived from swift

I am running project with lots of legacy code with objc and swift. I've been using objc MPOldKeychainManager , which is now deprecated and swift's NewKeychainManager is to be used.

The problem is following: MPOldKeychainManager had some categories written and I don't want to rewrite them as swift extensions. What I've done is:

  • naming the class derived from the NewKeychainManager (visible in " myTarget-Swift.h ") to " MPOldKeychainManager "
  • removing the objc declaration of MPOldKeychainManager

...hoping that the categories will still work.

objc(MPOldKeychainManager)
class NewKeychainManager: KeychainManager {
}

Unfortunately, old extensions can't see the MPOldKeychainManager (derived from swift), even though I've updated the imported header to myTarget-Swift.h

#import "myTarget-Swift.h" //previously - objc "MPOldKeychainManager.h"
@interface MPOldKeychainManager (Authentication)

Question: is it possible to use categories for objc classes derived from swift?

  • I have already tried totally new naming
  • I have already tried loads of clean-builds

In case you haven't seen it, here is a useful resource for migrating from Objective-C to Swift: https://developer.apple.com/documentation/swift/migrating_your_objective_c_code_to_swift . Among other things, it states that one cannot subclass a Swift class in Objective-C. What you are trying to do is specify a different Objective-C name, MPOldKeychainManager , for the NewKeychainManager Swift class.

This will, actually, work if you add an ampersand before objc , like so:

@objc(MPOldKeychainManager)
class NewKeychainManager: KeychainManager {
}

You can then use all your existing categories in Objective-C. You will, however, have a problem using them in Swift, because to be usable in Swift they need to be available in the bridging header, and you won't be able to use the class' Objective-C name ( MPOldKeychainManager ) in the bridging header.

You can, however, write an Objective-C wrapper class that will have a method corresponding to each category method and also taking a NewKeychainManager pointer. A wrapper method can then delegate to the category method, which is available to Objective-C code, so you won't have to re-implement your category methods in Swift.

Let's say an Objective-C category has method authenticateUser: :

@interface MPOldKeychainManager (Authentication)

-(void)authenticateUser:(int32_t)uid;

@end

The method could be wrapped as follows:

@interface OldKCMWrapper : NSObject

+(void)authenticateUser:(int32_t)uid withManager:(NewKeychainManager*)inst;

@end

This interface declaration must be available, directly or indirectly, via the bridging header. Then, somewhere in your Objective-C code, the wrapper could be implemented thus:

@implementation OldKCMWrapper

+(void)authenticateUser:(int32_t)uid withManager:(MPOldKeychainManager*)inst {
    [inst authenticateUser:uid];
}

@end

The wrapper can then be used in Swift code, eg:

let kcm = NewKeychainManager()
OldKCMWrapper.authenticateUser(321, with: kcm)

In fact, the wrapper could be used in a Swift extension of NewKeychainManager . You would still have a Swift extension with equivalents of all the Objective-C category methods, but you would not have to re-implement their code in Swift: methods in the extension would simply delegate to the wrapper.

Hopefully this is helpful. There are other ways of implementing this idea, possibly more elegant.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM