Import a Swift module in Obj C module - ios

I have a xcworkspace with two xcodeprojects inside (one is a static library where all the base functionalities are implemented and the other is a demo project which uses classes from first one) - and all the code so far has been written in Objective C. What I want to achieve is create a Swift class in the static library and then access it from an Objective C class in the 'demo' xcodeproj.
I have created this 'Test.swift' class and a bridging header that was created automatically (changed the Defines Module property to YES in the Build setting), and everything works well - I can access it from Obj C classes in the same project. Next, I am creating a new "DemoTest.swift" Swift class in the 'demo' project and subclassing the Test.swift (which works). However, when trying to access this class from an Objective C file in the 'demo' project, the compiler doesn't recognize my "base" module -
In file included from
xxxxx/AppDelegate.m:26:
xxxxx/mpdemo-Swift.h:189:9: fatal error: module 'mpbba' not found
#import mpbba;
~~~~~~~^~~~~
1 error generated.
My question is how can I have a Swift code imported into another Objective C module?

Here's what to do:
configure an Objective-C bridging header
Click on your Xcode Project file
Click on Build Settings
Find the Search bar and search for Defines Module.
Change the value to Yes.
Search Product Module Name.
Change the value to the name of your project.
In class, add the following: #import "YourProjectName-Swift.h"
Hope this will work. let me know if you need anything else.

Related

Hide Objective C in mixed Swift Cocoapod library

I am developing a Swift Cocoapod library which actually is a wrapper around some Objective C code.
My goal is to expose only the Swift part of the library, while making the Objective C
as private as possible. However, as the Swift part is a wrapper around the Objective C code, it needs to access it, although just internally.
I have searched and tried various approaches, but none of them worked at all.
First, I tried to address it via the use of a modulemap file. The idea was to create a Swift module called something like MyLibrary containing all the Swift code, while the Objective C code would be on the MyLibrary.Private module (I know the module would still be accessible, but this separation would be enough for me). The modulemap would look something like:
//MyLibrary.modulemap
framework module MyLibrary {
module Private {
header "MyObjectiveC.h"
export *
}
}
And adding the following line in the MyLibrary.podspec file
s.module_map = 'path/to/MyLibrary.modulemap'
However, by using this approach, even if I only import the MyLibrary module would still get access to all the Objective C classes, without having to import the MyLibrary.Private module to do so.
A second approach I tried was to make use of a private.modulemap file. So I would end up with two different modulemap files:
//MyLibrary.modulemap
framework module MyLibrary {}
//MyLibrary.private.modulemap
module MyLibrary.Private {
header "MyObjectiveC.h"
export *
}
I would then add the following line in the MyLibrary.podspec file
s.pod_target_xcconfig = { 'MODULEMAP_PRIVATE_FILE' => '$(PODS_ROOT)/MyLibrary/path/to/MyLibrary.private.modulemap' }
However, I get a failed build stating that it can not find the MyLibrary.Private module.
Is there anything I am doing wrong in these approaches? Or is there any other way to allow my library's Swift classes access the Objective C classes privately without exposing those, at least explicitly, requiring to import an specific *.Private module for it?

Cannot call value of non-function 'module<F1>'

I created a Swift framework, just a simple test.
The Swift file (F1.swift) code:
public class F1{
public init(){
print("inited")
}
public func call(){
print("called")
}
}
Then, I built the framework and I imported it into another project.
I tried to use it this way:
import F1
in the viewDidLoad of a UIViewController:
var c = F1()
c.call()
The F1.framework has been dragged under:
General > Embedded Binaries
General > Linked Frameworks and Binaries
and I can also see it under:
Build Phases > Link Library With Binaries
Build Phases > Embed frameworks
The XCode "reaction": no issues with the import statement.
I receive an error exactly where the class is instantiated:
Cannot call value of non-function 'module...'
Am I missing something?
[update] Based on some online resources and some other test, I'm supposing the problem lies in Build settings: eg. Build Active Architecture Only could be involved, but it would be interesting to understand how and why.
Find minimal sample Xcode project here.
Using your posted code gives the expected results here:
inited
called
In your example you've named the single class in your module F1 to the same name as the module, namely F1. Most likely Swift can't differentiate between module namespacing and the actual name of your class in the module, so when you just write F1, Swift possibly infers this to be an explicit namespacing annotation; refering to the namespace F1 (made available by your import of module F1). A namespace can naturally not be treated as a type, which would explain the error message you're prompted with ([emphasis mine])
Cannot call value of non-function 'module...'
You may test this theory by explicitly calling the class F1's initializer of module F1, by including both the module namespace and its (single) class type in the call:
var c = F1.F1()

Swift and Obj-c Interoperability issues while unit testing

I have an iOS application written in Obj-C which has unit tests defined as well. Now, i am adding a new feature where i am using a swift class (S) in an Obj-C class(O). I have the bridging header in place for both the main target and the test target. Till this point everything works really well.
Here's the problem,
If i want to create an unit test class(U) for class O in swift and run it, i get an issue saying bridging header not found. I am assuming this is because O uses S and these details are in the bridging header file and then again i am trying to use both S and O in U resulting the failure. If i add any other Obj-C class which doesn't use S, it works perfectly fine.
Here's what i have already done just make sure you know whats happening,
I have a forward declaration in O.h for class S because i know the O.h file will not support holding the -Swift.h import statement and hence it is in O.m file.
Is this scenario supported?
Class O uses Class S.
Class U can test class O by using class S.
Note: O->Objective-C
S->Swift Class
U->Unit test class in swift.
The answer was simple but not very evident. I had to place the import statements in the bridging header files in the order of the usage. For example: if one class has dependency on the other, then its important that you place the dependency's import statement first and then the calling class' file in the bridging header

Swift Compiler Error: Use of unresolved identifier 'name'

I tried to include a class called 'name' and I got an error:
Swift Compiler Error: Use of unresolved identifier 'name'
The class exists and doesn't contain any compile errors.
There could be a few possible issues.
One of the classes has a Testing target and other one doesn't. You have to even include all of your classes in the testing target or none of them.
If it's Objective C class, check that the class is in ObjectiveC bridging header file.
If it's NSManagedObject subclass. Add #objc(className) before the class declaration.
If it's part of a different framework, make sure that the class or function is public
I had this one too. You will probably find that your first class is included in your testing module and that "name" isn't. Simply, if you include a class in testing, then every class that it references has to be in testing.
I had this problem too. I was trying to reference Class 1 within the code in Class 2. My problem was that Class 2 had target memberships in A and B, and Class 1 only had Target Memberships in Class A.
You can fix this by opening the Utilities Tab (farthest right button on the top bar of the Xcode window), and make sure that the same boxes are checked for both classes in the Target Membership subsection.
Got problem solved by
Target -> Build Phases -> Compile Sources -> Adding the class file
Add one more to the list.
If it is part of another framework, make certain that the "Build Active Architecture Only" settings are the same.

Use of a class from a second target

As the IBDesignable attribute needs the designable class to be in a seperate target I created a second target which worked great in the designer. When I then tried to use the new class in my code I get the error
"Use of unresolved identifier 'CustomMarker'"
I have imported the second target in my main target -- import CustomViews -- and I can cmd+click the target name to see the main .h file that describes the target; where the class is included. The compiler still can't find the class in my code though.
Any thoughts?
I had the same issue. Fixed this by changing access modifier of the class to public.
#IBDesignable public class MyCustomView: UIView {
}
By default classes and methods will be at internal access level. If you want to use that out side of the target, you should mark it as public. Then only it will be the part of public interface(visible to outside of target)
second target must be of type "framework".
you must also link it in build phases like as an external framework. link binary with libraries must have a link to your customViews framework and embed framework must have that link too.
that should be enough.

Resources