Cannot extend CocoaPods class in my Swift class - objective-c

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?

Related

Problem with using Swift in Objective-C target

I have an old Objective-C project, which has multiple targets, and some of the targets share a framework (let's call it CJDataKit) that's also written in Objective-C. I'm trying to add some Swift code to my project, at least to the main app target, and have some limited implementation of it working, but I'm running into some issues whenever the Swift code needs to use or import the CJDataKit framework, or any header file that itself imports the CJDataKit framework.
What's Working
I wrote a basic UIView subclass in Swift (which didn't need any other code from my app), and I can use this in my Objective-C target, using #objc keyword and by importing "MyApp-Swift.h" in my Objective-C code.
I then wrote a new UIViewController subclass in Swift, and used a couple of simple Objective-C objects from both CJDataKit framework and non-framework classes. I did this by creating a bridging header file, and added the Objective-C headers there.
So far so good, and everything compiles fine.
What's Not Working
The problem happens if I try to import into Swift other Objective-C
files that might be importing the CJDataKit framework inside it. For
e.g. I wanted to write a Swift extension of an existing
UIViewController subclass (call is PageAViewController). This
subclass has imported multiple other header files. If I add it to the
bridging header file, I start getting build errors:
Include of non-modular header inside framework module 'CJDataKit':
'.../CJDataKit/Person.h'
Commenting out the #import CJDataKit makes it work for this particular file, but it still gets compile errors from a different header file (that was imported by PageAViewController). It'll only work if all the files imported don't have a #import CJDataKit, which is difficult and cumbersome. BTW, these files all belong to the app target, not the framework. So something about Swift doesn't like interacting with the CJDataKit framework directly, even though it works fine if it's built independently in the same app target along with the CJDataKit framework.
I've also tried importing the CJDataKit.h header file into the Swift
bridging header file, figuring this way I don't have to individually
import each file from the framework, but that doesn't work either.
That results in a different error:
Could not build module 'CJDataKit.h'
I've tried using #import <CJDataKit/CJDataKit.h> as well but same result.
From my settings:
- "Allow Non-modular Includes In Framework Modules" is Yes on the target, and framework. It is No at the project-level.
- "Defines Module" is also set to Yes, on both the app target and framework, and No at project-level.
Would love some help in getting this setup correctly. I've been searching for a solution, but haven't really found anything.

Adding objective c class that uses swift classes to bridging header Projectname_swift.h not found

I have an objective-c class that uses swift classes. It all works fine.
I wanted to import the objective-c class into a swift class, so I added its header file to the bridging header. All the sudden I got an error the Projectname_swift.h file is not found.
Any ideas how to resolve this issue?
Is it actually possible?
a circular reference has been created, making it so the Swift code is unable to compile (which leads to the canary error stating that the _Swift.h file is not found).
i have provided a more in depth answer to a similar questions here and here.
long story short, the documentation explicitly says not to this:
To avoid cyclical references, don’t import Swift code into an Objective-C header (.h) file. Instead, you can forward declare a Swift class or protocol to reference it in an Objective-C interface.
Forward declarations of Swift classes and protocols can only be used as types for method and property declarations.
in order to make your code compile again you will need to remove the #import "Projectname_Swift.h" line from the offending Objective-C header. ideally you can simply move the import statement into your .m file, however if you need to publicly expose the Swift class in your ObjC header, then you must forward declare it using #class SomeSwiftClass;.
Let the Xcode build the bridge file from Objective-C to Swift.
Create a temporary directory elsewhere. In there, you create a dummy Xcode Swift project, give the project name the same as your existing Current Project Name.
Then add new file, Objective-C (.m file). The XCode will prompt you to create a bridge header file, click on the create bridge file (the right most button).
Now you locate the header file location in Finder. Then drag into your Current Project of Interest, don't forget to checked the copy file if necessary option. Add necessary #import '.....' in the header file.
You should be good. If everything works fine, delete the dummy project.
Clean derived data. and then #import "ProjectName-Swift.h" in your objective c files.
Go to
Build Settings->Objective-C Generated Interface Header Name
and set the value to YourModule-Swift.h (this is usually already set, this is the filename you need to import on .m file #import "YourModule-Swift.h"
Go to Build Settings and search for "Defines Module", set both values to YES
Create a class in swift with prefix of #objc for example
#objc class mySwiftClass{...}
Build the project again
it will be better if you use error syntax or screen shot. you can simply try this
1. Goto your project on top of right navigation
2. select build settings from middle pain.
3. search for Objective-C bridging header
4. just below this you will find "Generated interface HeaderName"
5. add correct address of your swift file
6. clean and build the project.

How to import SKTUtils in Objective-C?

I'm trying to import SKTUtils - which is a set of swift files - into an Objective-C project. As far as I know it would be enough to do this way:
#import "ProjectName-Swift.h"
But the problem is that SKTUtils is not a project, but rather a directory with a set of swift classes. I tried to import the files this way:
#import "Vector3-Swift.h"
#import "CGFloat+Extensions-Swift.h"
.... etcetera ....
But without success. I've also set to yes the define modules option inside the project's build setting but still nothing to do.
I have just tried to import SKTUtils in blank Objective-C Xcode project.
Looks like you are missing the following part of requirement for correct bridging:
You need to import ProjectName-Swift.h. Note that it's the project name - the other answers make the mistake of using the class name.
This single file is an autogenerated header that defines Objective-C interfaces for all Swift classes in your project that are either annotated #objc or inherit from NSObject.
taken from How to import Swift code to Objective-C.
For example in my test project my Project-Swift.h does contain imports of SKTUtils's extensions of SKAction because they are Objective-C-based classes of SpriteKit but some other stuff is not Objective-C friendly that's why you cannot access it because it is just not generated in -Swift.h file.
Another example is that I start seeing SKTAudio class in my Objective-C code if I make it a subclass of NSObject:
#objc public class SKTAudio: NSObject {

Using Swift in Objective-C project

Although I have followed and tried everything from This Thread and read all of Apple's Guide of Swift-ObjC interoperability, I'm unable to recognize or use Swift fies in my project.
I have created a Swift file that declares/defines a class called TorusView that inherits from UIView. I've tried to gain access to this class in another class MenuView by importing the bridging header, importing the Swift class, importing the class with the syntax *-swift.h (which seems to now be *.swift.hin Xcode7.2). I've made all of the modifications to my target build settings recommended in that lengthy Stack question and a variety of others from google searches.
Nothing I've tried has allowed me to create a TorusView objective in my objective-C class.
You need to import a header file YourAppName-Swift.h, it contains all the public (and internal if same target) declared types in Swift.
first: Build Settings --> defines module --> YES.
second:Product Module Name -->YOUR project NAME.
last:improt "YOUR project NAME-Swift.h" in your Object-c file
like this:
enter image description here

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