2

I want to extend my class which I wrote in Swift. I want to write the extension in Objective C because I need to put some Objective C code which I can't port into Swift. I know that I can create a .h and .m and then include the .h at the bridging header. But in the .h, I need to include the original .swift class file right?

How can I solve this? Can I include using myclass-swift.h? Thanks.

Jamshed Alam
  • 12,424
  • 5
  • 26
  • 49
Chen Li Yong
  • 5,459
  • 8
  • 58
  • 124
  • I have little experience in Obj-C, but can't you just add a category to the swift class? – Sweeper Nov 02 '16 at 07:39
  • @Sweeper the problem is the code that I need to add is a copy-pasted code from other projects, which can't be converted into Swift because of incompatibility with the data type (I need to use pointer data type, which is non existent in Swift). – Chen Li Yong Nov 02 '16 at 07:53
  • Probably, it is not possible to have an ObjectiveC category for a Swift class. – Ahmad F Nov 02 '16 at 08:00
  • @AhmadF the problem is I don't know how to implement it, because of the problem presented above. I cannot include the original Swift class into the Obj C extension file because this is a Swift project. If I cannot include the original Swift class, how am I suppose to extend the class? – Chen Li Yong Nov 02 '16 at 08:04
  • "I need to put some Objective C code which I can't port into Swift" I don't know why, but in general I could say use your ObjectiveC classes into Swift extension – Ahmad F Nov 02 '16 at 08:17
  • @AhmadF oh I understand now, I forgot you have little experience in Obj-C. In Swift, everything is like already imported to one another. You create class `A` in file `A.swift`, and then when you create file `B.swift`, the class `A` is ready to be used in file `B.swift` without you even need to import `A.swift`. in Obj-C, importing is such a hassle. If I want to draw comparison in swift, I need to state `import A.swift` first in `B.swift` so I can use class A. But not even than, this is a different language we talking about, so I can't just `import A.swift` in a Objective C code file. – Chen Li Yong Nov 02 '16 at 08:31
  • @AhmadF that's why we have "bridging header", which we state all the foreign language source file in there to be included, and then we use their contents just as if it were written by the project's current language. But in this case, the extension I'm going to write is the *foreign* ones, so I can't use the bridging header to help me import the native language source code so that my *foreign* source file can know about the class I'm going to extend, because that's not how bridging header works. – Chen Li Yong Nov 02 '16 at 08:34

2 Answers2

1

The following documentation may be helpful: https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html#//apple_ref/doc/uid/TP40014216-CH10-ID122. You've probably already looked at that, but just in case. The following question may also help: Extending a Swift class with Objective C category.

As you know, to use Objective-C code in Swift there is the bridging header. To go the other way around, there is the auto-generated *-Swift.h header that should be imported in .m (and .mm) implementation files. The documentation says it should not be imported into .h files. In fact, the compiler won't let you import it into a .h file that is included, directly or indirectly, in the bridging header. However, with some care you can import it into other .h files.

Now, suppose your Swift class is called SwiftClass and you want to add to it a method called ocFunction() implemented in Objective-C. One approach, essentially presented in the aforementioned answer, is to implement a category in an Objective-C source file (.m):

@implementation SwiftClass (OCExtension)
-(void)ocFunction {...}
@end

Then modify your SwiftClass to include the following:

class SwiftClass : NSObject
{
...
    @nonobjc func ocFunction()
    {
        self.perform(Selector(("ocFunction")))
    }
...
}

The referenced answer suggests doing this in an extension, but since you have full control of the SwiftClass source, you can just do it in the class directly. BTW, the Objective-C category function could be named something other than the SwiftClass's function, thus eliminating the need for @nonobjc.

Another approach might be to define an Objective-C wrapper interface like this:

@interface SwiftClassOC : NSObject 
+(void)ocFunction:(SwiftClass*)sc;
@end

and make it available to Swift via the bridging header. The implementation would go into a .m file. Then your ocFunction() in SwiftClass would look like

func ocFunction()
{
    SwiftClassOC.ocFunction(self)
}

Please note that SwiftClassOC is stateless, so it's essentially a set of helper functions that take a SwiftClass pointer. SwiftClass is the one maintaining the state.

Community
  • 1
  • 1
Anatoli P
  • 4,791
  • 1
  • 18
  • 22
  • This is actually a great solution! Never thought that I can perform selector and the selector can call the obj-c version of the class! Thanks! – Chen Li Yong Nov 07 '16 at 08:14
0

You can extend an Objective-C class with Swift, but you cannot extend a Swift class with Objective-C.

I want to write the extension in Objective C because I need to put some Objective C code which I can't port into Swift

You can do that, but not as part of the Swift class. What I usually do is make a "helper" class in Objective-C and import it into Swift.

matt
  • 515,959
  • 87
  • 875
  • 1,141