Swift autogenerated header missing new swift classes - objective-c

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.

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.

Force Product-Swift.h to update

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!

Cannot extend CocoaPods class in my Swift class

I've tried following the tutorial at https://vimeo.com/107295686, and failed very early.
Basically, I've:
created project
created Podfile which requires BDBOAuth1Manager and AFNetworking
installed cocoapods, closed XCode, and reopened it in my MyProject.xcworkspace directory.
Created and deleted a dummy Objective-C file, because I needed bridging header
Added #include directive to this header, which asks for BDBOAuth[...].h
Created Cocoa Touch class which extends BDBOAuth1RequestOperationManager
This is my code:
import UIKit
class RESTClient: BDBOAuth1RequestOperationManager {
}
And now I can't instantiate my new Cocoa Touch class.
When I try to call constructor, this is the hint I get
Note that method description says "Initializes an instance of the class that implements the video compositing protocol", which has nothing to do with my OAuth intentions. When I switch back to my class, and command-click the class I've tried to extend, I get the correct file with correct init params.
Any help will be appreciated
When I was trying to do this exact thing (same library), I had to change the import statements in BDBOAuth1Manager to use
#import <AFNetworking/xxx.h>.
My project wouldn't build without it. Have you checked the header search paths?

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

How can I add forward class references used in the -Swift.h header?

I'm integrating Swift code into a large Objective-C project, but I'm running into problems when my Swift code refers to Objective-C classes. For example, suppose I have:
An Objective-C class called MyTableViewController
An Objective-C class called DeletionWorkflow
I declared a Swift class as follows:
class DeletionVC: MyTableViewController {
let deleteWorkflow: DeletionWorkflow
...
}
If I now try to use this class by importing ProjectName-Swift.h into Objective-C code, I get undefined symbol errors for both MyTableViewController and DeletionWorkflow.
I can fix the problem in that individual source file by importing DeletionWorkflow.h and MyTableViewController.h before I import ProjectName-Swift.h but this doesn't scale up to a large project where I want my Swift and Objective-C to interact often.
Is there a way to add forward class references to ProjectName-Swift.h so that these errors don't occur when I try to use Swift classes from Objective-C code in my app?
You can create another header file that forward declares or imports the necessary classes, and then imports ProjectName-Swift.h. For example, create a file named ProjectName-Swift-Fixed.h with the contents:
// ProjectName-Swift-Fixed.h
// Forward declarations for property classes
#class DeletionWorkflow;
// Imports for superclasses
#import "MyTableViewController.h";
#import "ProjectName-Swift.h"
Then, instead of #import "ProjectName-Swift.h" in your codebase, use #import "ProjectName-Swift-Fixed.h.
This is a little silly, but it sounds like your "workaround" is what Apple intended, at least for now. From the interoperability guide:
If you use your own Objective-C types in your Swift code, make sure to import the Objective-C headers for those types prior to importing the Swift generated header into the Objective-C .m file you want to access the Swift code from.
In this devforums thread, someone mentioned they already filed a bug in Radar. You probably should too.