Force Product-Swift.h to update - objective-c

I'm using both Swift and Objective-c code in my app.
problem is, sometimes after updating a class thats written in Swift, Then trying to use it from a class written in objective-c, the changes have not updated at the 'Product-Swift.h' file!
Is there any way to force this update manually?

Ok I found it!
So the init method was not generated to Product-Swift.h file, here it is:
internal init(transitionNavigator : TransitionNavigator,bundleSelected bundle : Bundle) {
The problem was the 'TransitionNavigator' file was written in swift too, and once I marked the class with #objc :
#objc class TransitionNavigator {
It solved it!

Related

Swift CocoaPod Library in Objective-C Project Migration from Swift 3 to 4/5

I'm using a Swift CocoaPod in my Objective-C project. Originally it was a Swift 3 project and I simply had to add the #import "<Project Name>-Swift.h" into my .m or .h file. I've since updated to the latest version of the CocoaPod which I believe is now Swift 5. Therefore this is no longer working as none of the properties can be found.
I've looked at a number of different resources online including Apple's documentation and the procedure is unclear here what to do. It seems I have to go in and edit the .swift file and add #objc in front of each property or method I wish to access? This seems to go against what CocoaPods is about as the next time I update all my changes will be blown away.
I tried looking at the generated header but when I highlight the #import "<Project Name>-Swift.h" line I just get taken to the NSObject declaration. Obviously it is just a build time item I'm guessing.
According to the Apple documentation (https://developer.apple.com/documentation/swift/imported_c_and_objective-c_apis/importing_swift_into_objective-c) the Swift declarations must be marked with the public or open modifier and when I checked the swift file I found that they indeed are.
The pod I'm using is HGCircularSlider. An example of what I'm trying to access is in the RangeCircularSlider class is here:
open var startPointValue: CGFloat = 0.0 {
didSet {
guard oldValue != startPointValue else { return }
if startPointValue < minimumValue {
startPointValue = minimumValue
}
if distance > 0 {
endPointValue = startPointValue + distance
}
setNeedsDisplay()
}
}
As we can see here the declaration is public. I'm assuming I need to set some sort of build setting?
In addition I have set use_frameworks! in my Podfile. I've also checked that the build target within the pod project and Objective-C Generated Interface Header Name is HGCircularSlider-Swift.h. This is exactly what I'm using in my Objc .m file.
Welcome any thoughts or comments where else I should look?
Update 1
One other thing of note. In my .h and .m I have a #property of type RangeCircularSlider which it can see fine. No error there. It's accessing the properties and methods within the object that is causing the errors.
Property 'startPointValue' not found on object of type 'RangeCircularSlider *'
So it sees the swift file but as originally stated, no properties can be found.
Update 2
So I've discovered that if I add #objc to the front of the individual properties I'm trying to access in the Swift file the generated header file then see's them and I can therefore access them. So for the example function above it would then be
#objc open var startPointValue: CGFloat = 0.0 {
But these seems to be a bit of a hack as for when I want to install an updated version of this CocoaPod, then those changes I made to the pod's file would be blown away.
Any suggestions how to do this without having to edit the swift files in the CocoaPod?
For anyone else that runs across this. The online resources I found were helpful but didn't detail this specific case.
First off. Leave the CocoaPod code as it is. This will allow you to update it without having to worry about modifying it each time.
Next create a Swift file within your Objective C Project. xCode will ask if you want a header generated for it, say yes. This file will be called -Swift.h.
In this Swift file subclass the Swift file from the CocoaPod you are interested in accessing.
For example :
import Foundation
import HGCircularSlider
class CircularSliderObjc: RangeCircularSlider {
}
Next add in the properties you wish to access with getter and setters.
#objc override open var startPointValue: CGFloat {
get {
return super.startPointValue;
}
set {
super.startPointValue = newValue;
}
}
Then finally change the import in your Objective-C file to your project's generated header file that I mentioned above (#import "-Swift.h"
). If you have a property pointing to the class in the CocoaPod change it to your new Swift Class. For example :
#property (weak, nonatomic) IBOutlet CircularSliderObjc *rangeSlider;
In this example I have it setup as an Outlet for InterfaceBuilder.
After that, you're done. It seems like a lot of work but it's quite easy and simple. Not quite as fast as just importing the header but since Swift 4 and 5 you can no longer just access open vars in Swift as properties in objc. They need the #objc declaration to make that work. Added security to the language I'm guessing.
Hope this helps someone.

Swift autogenerated header missing new swift classes

I am working in this project where I have a mix of old pre-ARC et ARC Objective-c files co-existing with swift since the start of the year. For some reason, that I can not find, to day all new Swift files I have added set to public are not being added to the Swift auto-generated header.
I have check target ownerships, build phase, that it is public as #objc and inherits NSObject. still I can not call the class from Objc and I can from other swift class. it is as if it was set to be private to the swift module or something even after setting it access public..
for example :
#objc public class SomeSwiftClass: NSObject
{
public func sayit()
{
print("Hello!")
}
}
this does not show in any of the OBjc classes where project-swift.h is imported. I am able to call previously created classes, but not the one I added today.
I would guess that some setting is wrong if all my classes are no longer available, but no just the new class !!?!??!?!?!?!?!?!?!
Edit:
- restarting Xcode does not fix it.
- rebooting system does not fix it.
- deleting derived data does not fix it.
strange thing building while having 1 line of code in Objc accessing the swift class does not cause an error. So Its looking like some type of problem with code completion.

Writing tests for swift classes with XCTest written in Objective c

I'm facing a problem trying to write a test for class written in Objective-c and gets injected with a class written in Swift.
Example in the Test file:
SomeSwiftClass *swiftVar = [SomeSwiftClass new];
SomeObjectiveCClass *objVar = [[SomeObjectiveCClass alloc] initWithSwiftClass:swiftVar]
But the complier doesn't recognize the Swift class, and it doesnt support importing the "Target-Swift.h" too..
How can I write a test for both Objective c and Swift at the same TestFile ?
There are quite a few things that need to be in place if you want to use a Swift class in Objective-C.
The bridging header is required "Target-Bridging-Header.h"
Precede the class definition with #objc in the .swift file.
If you're still stuck, try deleting your .swift files and adding them to the project again, and Xcode will ask to generate the bridging header for you.
Check out the documentation: https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html#//apple_ref/doc/uid/TP40014216-CH10-ID138
Or this link:
Swift to Objective-C header not created in Xcode 6
I managed to get it working, so if you post more of your code or share what you're doing I might be able to help.

Xcode pluginDidLoad not getting called when adding objective-c file in swift plugin

I'm working on a plugin for Xcode. It is supposed to be written in Swift.
When I start with a fresh plugin project (I'm using this Xcode Plugin template which is also available via Alcatraz) the project compiles and runs fine.
The pluginDidLoad method is getting called right after Xcode starts. As soon as I add any Objective-C file (and a bridging header of course) the pluginDidLoad method is not getting called anymore.
The Objective-C file might be as simple as an empty class that is a subclass of NSObject.
Removing the target-memberbership (for the plugin-target) from the newly created Objective-C (.m) file the aforementioned mentioned method is getting called again.
Has anyone developed a Xcode plugin in Swift that also uses Objective-C files before and got this working?
Update
It seems that my original solution only works with Swift only projects because Xcode always takes the objective c class if you have one.
So here is another trick: Extend the NSObject class by the function class func pluginDidLoad(bundle: NSBundle) {} and initialize your plugin there. Then it doesn't matter on which class it is called. You might have to check that also all Swift classes subclass NSObject. I pushed it to my repository that you can have a look
Original Post
I think I could reproduce the problem now. To simplify the problem, let's say that we have only two swift classes PluginMain and PluginHelper.
As you said, sometimes the plugin isn't getting called for some mysterious reason. I was struggling with the problem again and I was wondering how Xcode knows which class is the main class. So I came up with the idea to put the following initializer in both classes PluginMain and PluginHelper
class func pluginDidLoad(bundle: NSBundle) {
let appName = NSBundle.mainBundle().infoDictionary?["CFBundleName"] as? NSString
if appName == "Xcode" {
//sharedPlugin = SwiftySafe(bundle: bundle)
//initialize your shared plugin
}
}
By putting a breakpoint or log message in pluginDidLoad in both classes, I notices that Xcode isn't ignoring the plugin, it is just loading the wrong class (e.g. PluginHelper instead of PluginMain).
The Solution
It turns out that Xcode uses the class that is compiled first as the main class and calls pluginDidLoad only on that. So you can change that by reordering the "Compiled Sources" under your target settings->Build Phases. Move your main class so that it is on top. In the following image you find an example from my project. SwiftySafe is my main class.
My example
You will find my project here https://github.com/creinders/SwiftySafe if you want to compare the settings.
The pluginDidLoad method is called on the principal class. When the principal class is a Swift class, you have to include the module name in the NSPrincipalClass Info.plist key.
So if your target name is MyPlugin and your principal class is MyClass, set NSPrincipalClass to MyPlugin.MyClass.
Also make sure that MyClass inherits from NSObject.
Sometimes you need to tell Xcode to reload bundle. Run this and restart Xcode
defaults delete com.apple.dt.Xcode DVTPlugInManagerNonApplePlugIns-Xcode-7.3

#import "Project-Swift.h" File does not refresh

I have a project with Swift and Objective-C code. In my current project I have the problem that the #import "Project-Swift.h" file does not refresh if I add new Swift modules.
#import "Project-Swift.h" // does not refresh if I add .swift files
So in the Objective-C universe, the swift code is not available. the files exists, but does only contains default #defines etc. No project related stuff.
Clear Cache, rebuild, delete Derived Data does not help.
Solved it. Forgot #objc(<class>). It is mandatory.
Details here (Migrating)
Migrating Objective-C Code to Swift
And here (Swift Type Compatibility)
Interacting with Objective-C APIs
In my case it worked by building for the other target I had on my project:
Check you have prefixed your class with #objc
Choose the other scheme (target)
Build || Run
The bridging file updates
Change the scheme back to the target I was working on
Just use #objc before Swift Class that you want to use in Object-C code then Build the project.
For example:
#objc class Person : NSObject
{
// Swfit code goes here.
}
Now #import "Project-Swift.h" will be available in you project to use.