Short-circuit when using a Swift protocol - ios

As known, it is not possible to include the interface header file from a file in the -Header.h.
My actual problem is that I have the definition of a class one protocol of which is a Swift one:
#protocol arrivingDelegate;
#interface palettaTraffic : NSObject<MKMapViewDelegate, arrivingDelegate> {
}
If I import the *-Swift.h file I get into the ugly cycle when the file is included in another one that is included in the header file.
This is what happens when I use the #protocol directive: it is a warning, but quite a disturbing one.
This is how the swift protocol is defined:
#objc public protocol arrivingDelegate {
func submitManualBusLine(busStripe:StripeProtocol)
}
I also found a similar post:
Swift protocol in Objective-C class
But none of the suggestions seem to apply.

If I import the *-Swift.h file I get into the ugly cycle when the file is included in another one that is included in the header file.
Okay, but that is what you have to do. I don't see you doing it the screen shot above, which is why your protocol is not being seen.
The solution to the "ugly cycle" should be just a matter of tweaking the order in which things are imported in your various Objective-C files.

Adopting swift protocols in Objective-c is a tricky process. I fixed the issue by porting the adopting class to Swift too.

What I tend to do in my projects is putting the protocol conformance of the ObjC class in a Swift file, to avoid this error. Usually the file where the protocol is defined.
extension PalettaTraffic: ArrivingDelegate {}
Why? We're migrating our codebase from ObjC to Swift, but we cannot migrate every class at the same time. Because of this we have a large 'seem' between Swift & ObjC where Swift types need ObjC and vice versa. For me, this is the solution that causes the least amount of work right away.

Related

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, e.g.:
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.

No type or protocol named 'AVCapturePhotoCaptureDelegate'

I'm trying to use my Swift class into Objective-C code and I came across this answer to do so. However, after import MyModule-Swift.h, I'm getting compile error in MyModule-Swift.h:
No type or protocol named 'AVCapturePhotoCaptureDelegate'
Even though it contains #import AVFoundation; at the top. I'm clueless how to solve this. All I'm trying to do is to use one of the model class (written in Swift) in Objective-C.
I think you are using .mm file.
Use .m instead.

In our Swift file, where do I import the swift module?

I am reading matt's iOS pragraming book, when I read here:
Swift itself is defined in a module — the Swift module. Your code always implicitly imports the Swift module. You could make this explicit by starting a file with the line import Swift; there is no need to do this, but it does no harm either.
That fact is important, because it solves a major mystery: where do things like print come from, and why is it possible to use them outside of any message to any object? print is in fact a function declared at the top level of the Swift module, and your code can see the Swift module’s top-level declarations because it imports Swift. The print function thus becomes, as far as your code is concerned, an ordinary top-level func‐ tion like any other; it is global to your code, and your code can speak of it without specifying its namespace. You can specify its namespace — it is perfectly legal to say things like Swift.print("hello") — but you probably never will, because there’s no name conflict to resolve.
Such as, in my test ViewController:
import UIKit
//import Swift // here we can import Swift. it is okay
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
Swift.print("hello, matt") // where we import the Swift ?
}
}
We can use print or Swift.print, I just want to ask, how apple implicitly imports the Swift module ? and obvious, UIKit, we must import, if can implicitly imports Swift module, why there apple do not implicitly imports UIKit?
My confuse is how implicitly imports the Swift module?
The implicit import of the Swift module is a behaviour hard coded into the Swift compiler, exclusively for the Swift module.
Refer to Alexandex's, I finnaly find the doc
And we can see Clang importer:
The Clang importer (implemented in lib/ClangImporter) imports Clang modules and maps the C or Objective-C APIs they export into their corresponding Swift APIs. The resulting imported ASTs can be referred to by semantic analysis.

Is it possible to change when the (Project)-Swift.h header is generated?

I'm facing the following problem :
I've declared an protocol in a Swift file and I want to implement it in Objective-C.
I added the #objc annotation to my protocol so Xcode can generate a definition inside my (Project)-Swift.h file and it works fine.
However I cannot import the (Project)-Swift.h file in any of my objc headers since (I suppose) it is generated after those headers has been processed. It is not a big deal because I can simply use this workaround in my objective header file :
#protocol MySwiftProtocolName;
It compiles and works just fine but it will also throws a warning for each class that implements my swift protocol :
Cannot find protocol definition for MySwiftProtocolName
So my question is : Is it possible to force Xcode to generate the (Project)-Swift.h file before it starts processing the regular .h files ?
Thanks
You should be able to add #import "(Project)-Swift.h" into the file where you do implementing this swift protocol. Some times Xcode syntax gets funny and not autocomplete this header name, but in compile time it should work.
If it's not could you please provide more context of what is protocol looks like, as it may be not commutable with Objective-C and so it's not get generated at all.

Swift build error (involving word "class" as argument) with subclassed Objective-C class

I have a build error when trying to subclass a custom Objective-C class (a subclass of UIViewController) in Swift.
When I try to subclass in Swift, I get the build errors in the picture below. All of them relate to the use of the word class as an argument in the OCMapper library (where I've opened an issue as well).
Some more notes:
In the project, I both import and use Objective-C code in the Swift code and import and use Swift code in the Objective-C code.
I import the compiled Module-Swift.h only in .m and .mm files and forward declare classes that I need in .h files.
I've attempted to create a Module-Swift-Fixed.h class where I forward declare and/or import the custom Objective-C class headers (as recommended here), but that hasn't made a difference.
Has anyone seen anything like this before or have a solution?
I have as yet not been able to trace where in the language spec this is documented, but I suspect you have come across the same problem that I recently faced in objective-c since moving to Xcode 6.4.
I had a message (method) defined as follows
- (BOOL)canProcessClass:(Class) class {
return [class isSubclassOfClass:[NSSet class]];
}
with the same compile error as you mentioned Expected identifier. The fix was simple - just rename the the class argument to something like classToProcess. Which would give you the following
- (BOOL)canProcessClass:(Class) classToProcess {
return [classToProcess isSubclassOfClass:[NSSet classToProcess]];
}
Hence just rename the arguments in your Swift code to not use the (key)word class and you should be fine.
If anyone can point me to the language spec that documents this I would really appreciate it. As far as I'm aware you shouldn't use Class, but I haven't able to find anything about class except the obvious that it is a message (method) available on classes.

Resources