Unknown class in Compiled Swift Framework embedded in Objective-C Project - objective-c

I have a framework binary built with Swift that I'm trying to incorporate into an Objective-C project. However the class in the framework isn't available.
In the swift framework, the class is defined like this:
#objcMembers
#objc public final class Messaging: NSObject, UINavigationControllerDelegate, LogsManagerDelegate {
...
}
I drag the archived and exported framework directly into the project to use and make sure the Defines Module is set to Yes in the Build Settings.
In the Objective-C I try to use the framework:
#import ContactAtOnceMessaging;
#implementation MessagingExperience
Messaging *messaging; // Unknown type name 'Messaging'
...
#end
If I drag the code for the framework directly into the project, Messaging is a known class so I know the Swift is okay.
I also tried changing the import to the following, but that didn't work.
#import "ContactAtOnceMessaging/ContactAtOnceMessaging-Swift.h"
I also tried using CocoaPods to import the framework and that hasn't helped.
What am I doing wrong?

I can confirm that I experienced the same problem as you. I was also able to resolve it. I'm not sure if the original problem was caused by an anomaly somewhere in my configuration. I did, however, test the following procedure and found it to work reliably with Xcode 9.3.
I first made a test Swift framework named Dynamic-Framework-Tester, in an Xcode project, and set it to be copied to an absolute path on every build.
I then performed the following steps to setup my Objective-C project:
Made a new project with Objective-C as the language.
Dragged the framework from its absolute path into the project without choosing "Copy items if needed".
Deleted the framework from Linked Frameworks and Libraries because it will get added automatically in step (4).
Added the framework to Embedded Binaries.
In build settings, set Always Embed Swift Standard Libraries to Yes.
Added my custom framework path to the Framework Search Paths setting in the build settings.
In the Objective-C project, I imported the framework using
#import Dynamic_Framework_Tester;
and called a method exposed in the framework from Objective-C.
Using a simulator, I was able to update the framework and have the changes applied on subsequent runs of the app.

Related

Creating pod in swift which have dependency on another objective-c pod

As I explained in image I want to create Pod lib in swift which have another Pod lib dependency written in Objective-c.
Now I know that to use objective-c code in swift we need bridge file and I created it too.
but When I set it into Pod's build phase I got this error<unknown>:0: error: using bridging headers with framework targets is unsupported
I got hint in internet that I should put .h file into pod-umbrella.h file, But that also gave me error Include of non-modular header inside framework module 'DemoPod'
Please help me if you had similar issue in past and resolved it.
Some hint/suggestions are also welcome.
Here is my demopod project for you if you want to play around.
Demo Pod Project
EDIT
As per Ashsis suggestion I added below code into DemoPod.modulemap
framework module AdaptiveCard {
umbrella header "/Users/jageen.shukla/Documents/Project/ai answer/DemoPod/Example/Pods/AdaptiveCards/AdaptiveCards.framework/Headers/ACFramework.h"
requires ios
export *
}
But still I can not build project because it give me error in target project that can not find module "AdaptiveCard".
I change code in DemoPod.modulemap
framework module DemoPod {
umbrella header "DemoPod-umbrella.h"
// Solution 2
framework module AdaptiveCard {
umbrella header "/Users/jageen.shukla/Downloads/DemoPod/Example/Pods/AdaptiveCards/AdaptiveCards.framework/Headers/ACFramework.h"
export *
module * { export * }
}
// ----
export *
module * { export * }
}
Now I am able to compile my project. but I am not sure what I am doing is good practice or not? Plus I am also not know why I have to mention `absolute path` of adaptive card's header file.
Latest code : [Demo_2][4]
https://drive.google.com/file/d/1Xve0DUAy4bQ7sx4d3H8WLbJJwTqlJnCt/view?usp=sharing
Bridging header is only recommended at App Target and App Test target to access objective c and CPP files in swift. You should use modulemap to expose the Objc and CPP functionality to swift library when it comes to static library or framework. Please check the code implementation how to use modulemap here: https://github.com/ashislaha/Swift-ObjectiveC-Interoperability
As the error says, bridging headers aren't allowed in frameworks, only in applications.
The detailed documentation is here
The Swift code will be able to access everything from objc that is included in the public umbrella header for your framework where it says
// In this header, you should import all the public headers of your framework using statements like #import <YourFramework/PublicHeader.h>
You'll need to remove the bridging header from where you added it in the Build Settings, in order to get your framework to compile.
what should you do now ?
do this:
Remove your bridging header file.
Remove references to the bridging header file in the build settings for the framework
Add the necessary headers to your umbrella file ([Name].h)
Make the included files public in the framework's "Headers" section of its "Build Phases".
Clean and rebuild.
Note: The "umbrella header file" is a file (named [ProductName].h) that generally represents all public headers of a framework. It is usually just a list of #import statements to other headers contained in the framework. In Xcode, if you open UIKit.h, you will see a good example of an umbrella file.

Swift framework: using oc framework or static library with modulemap

I currently making a Swift framework, and my Swift framework depend on other oc framework and static library.
So i need to import them with modulemap.
But modulemap can only writen in abosuled path, this is very unfriendly for a team work.
I have tried to use aggregate target and write the script in build phases(script can use relative path to build module), but this cause another problem. The Swift framework product generate two modulemap, and when my project using this framework, xcode says it couldnt find the module that it generate by the aggregate target!
What can i do?
Finally, i find a way to solve all the problem.
Cause Swift need modulemap to use the third party framework, i make an umbrella framework to wrap all the .a and .framework files, and make them public. Then make all .h file written in the umbrella file.

In a mixed objc/swift module, Xcode always tries to include the module itself

This one is not easy to explain, but is also very annoying.
I'm working on a Cocoapods framework (in development mode) with objc and swift sources. Let's call it the "SuperCompoment" framework
Xcode auto generates the SuperComponent-Swift.h file, to make Objc classes visible from Swift ones.
Some Objc classes also includes Swift classes.
At compile time, in the SuperComponent-Swift.h, Xcode adds the line
#import <SuperComponent/SuperComponent.h>
... and fails to compile with the message: SuperComponent/SuperComponent.h file not found
Xcode tries to include the framework inside the framework itself!
If I manually edit the auto-generated file by commenting the #import, the project compiles perfectly. But Xcode auto-generates the file after each clean and before archiving the project!
Any clue?
I don't know why Xcode automaticaly adds the #import <SuperComponent/SuperComponent.h> line (since it do work without it), but if i'm kind with him by adding an empty SuperComponent.h file at the root of my framework, it compiles gracefully.

PojectName-Swift.h Not found while using Both Swift and ObjC codebase

I had a perfectly working ObjC project integrated with Apple WatchKit App with Multiple Targets. Only one of the Targets is linked with the WatchKit App.
I am moving my classes to swift and hence there are ModuleName-Swift.h files being used in my code.
Followed steps given in ModuleName-Swift.h file not found in xcode8 and I have ensured to add the “$(PROJECT_NAME)-Swift.h” under Projects > Build Settings > Objective-C Generated Interface header name.
But when I go to the build settings - it shows as Objective-C generated interface header name for the project target and Swift_ObjC_Interface_header_name for WatchKitApp Target
Error thrown by compiler : ProjectName-Swift.h file Not found
Is this causing the error? Not sure what I am Missing.
This is how I've linked the -swift.h files in Other targets
The issue was:
There were Unit test cases that were failing, disrupting further Compiling of the Project
Quick Fix:
The ObjectiveC Classes had Unit test cases associated with it.
Some of the Unit tests were failing due to changes to the main code base.
I had to uncheck the the following under Edit Schemes > Build so that they don't Build while running the WatchKit App.
I agree I will have to update the test cases to work with the Updated app, But the issue of Watch App not working is Fixed! :)

Dependency Management for iOS Library

First off: Why is dependency management for obj-c projects such a pain?!
I am writing a wrapper for my RESTful service in objective-c. The server is a simple sinatra app running locally on 'http://localhost:4567'.
I've included RestKit by following the steps outlined here.
I know RestKit is 'installed' correctly into my project because when I do #import <RestKit/RestKit.h> the project builds just fine.
Now, I'm testing my library using SenTesting.Framework. I have a class in my main library that looks like this:
#import "CITWCore.h"
#import <RestKit/RestKit.h>
#implementation CITWCore
- (id)init
{
self = [super init];
if (self) {
RKObjectManager *manager = [RKObjectManager objectManagerWithBaseURL:#"http://localhost:4567"];
// Initialization code here.
}
return self;
}
#end
And my unit test class:
#import "CITWCoreTests.h"
#implementation CITWCoreTests
- (void)testItCreatesAnInstance
{
CITWCore *newCoreObject = [[CITWCore alloc]init];
STAssertNotNil(newCoreObject, #"new object should not be nil");
}
#end
When I run the tests using ⌘U the test fails with this message:
error: testExample (CITWCoreTests) failed: -[__NSCFString isIPAddress]: unrecognized selector sent to instance 0xa115880
The error is being triggered by line 292 in RKClient.m
if ([newBaseURLString isEqualToString:#"localhost"] || [hostName isIPAddress]) {
There is a header file in the RestKit project called "NSString+RestKit.h" which contains the -isIPAddress method declaration, and as far as I can tell it is getting included, so I have no idea why the compiler/run-time does not know about that particular method. Is there something wrong with the way I've configured my testing target? How can I create an instance of RKObjectManager and get this test to pass?
More abstractly: How are people managing dependencies like this? I'm looking at things like VenderKit, but it seems lacking in documentation and I don't think I have the proper understanding of how compilers and linkers work to go to that big of an abstraction. What are some general guidelines when linking static libraries into my project, which is itself a static library?
Double check that your project build settings for "Other Linker Flags" has "-all_load" and "-ObjC" on your build target. While you are in there, check that you created the "Header Search Paths" entry ("$(SOURCE_ROOT)/RestKit").
The "Installing-RestKit-in-Xcode-4.x" page that you linked to, is slightly out of date with a) Xcode and b) RestKit HEAD (the build process was simplified recently. FMI see the mailing list.
If you want to see a project correctly setup (I just created it recently, with the newest Xcode and Restkit) take a look at https://github.com/lottadot/lottadot-restkit-ios-rails3-1-advanced
My guess is if you clone that project, edit it's configuration and remove "-all_load" you will see the exact same error, when you run it.
In this case, you need to find the file (or image/library) which defines/exports -[NSString isIPAddress]. Then you would need to add that file to your compile phase (if it is a source file), or link the library to your final binary (if it is a library or object file). In addition to linking it to your app, you will also need to compile and or link it into your unit test executable.
I know RestKit is 'installed' correctly into my project because when I do #import the project builds just fine.
#importing will not necessarily link or compile all of the necessary dependencies. You may have to do this manually. Xc4 may detect the dependency automatically, and build and link it for you if the option is enabled -- but it does not always get it right (it's good for basic dependencies).
Why is dependency management for obj-c projects such a pain?!
It's really not, IMO. Specifying files to compile and libraries to link with is something you'll need to get used to when compiling C family languages. Unless you want to be more specific about this criticism…
How are people managing dependencies like this?
Add the dependent projects to your Xcode projects. Configure them as build dependencies -- this will ensure they build before your app is built, and that the builds are up to date. For static libraries (targeting iOS), save the link stage for the final executables. In more complex scenarios, you will want to use xcconfig files in order to easily define build settings for any/all dependencies.
One simple solution is to use cocoapods, which is good dependency management tool similar to maven in Java world.
CocoaPods is quite a powerful and maturing dependency management tool that can manage libraries, the libraries these depend on (transitive dependencies) as well as compiler and header flags.
It works by linking your project to another workspace that includes the libraries in source form, where the main target emits a static lib. This gives a good compromise between speed and being able to see the source-code.