Hide Objective C in mixed Swift Cocoapod library - ios

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?

Related

F# Library structure

I'm doing some restructuring of a project of mine, and decided to make a separate library project for a big part of it.
My problem lays in that I have multiple files with modules where many of them should be hidden from user API, how do I achieve this? I have not tried this before so are unfamiliar to how the library structure are different from commandline projects, and how to scope things correctly. If I can see every file in the lib project from
other project why do we have the Library.fs file?
To formalize a little. Say that I have SomeCode.fs and Library.fs
SomeCode.fs
module SomeCode
type SomeType = ...
let someFunc1 ... = ...
// things to hide here
// depend on hidden code
let SomeFunc2 ... = ...
Library.fs
namespace SomeLib
module Mod1 = ...
This is intended to target other F# project. How to structure this so the API would only see the right things, and still be maintainable?
internal is your friend here. If you declare a module
module internal MyNamSpace.MySecretModule
this is only accessible from within your project.
The module Library you keep public, and this is your API.
internal can also be used on individual functions, in case you want to hide just some functions.
A fairly common way of hiding part of a module is also to employ the following pattern
module MyModule =
[<AutoOpen>]
module internal MySecretModule =
let apa = 1
// Bunch of other internal stuff
// Can use stuff from MySecretModule, but other projects cannot
let bepa = apa + 1

Import a Swift module in Obj C module

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.

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 How to make protocols imported imported from another module accessible outside of current module

Using swift I created a framework Common that contains functions and protocols I use repeatedly to cut down on code reuse.
Common.framework
public protocol CommonProtocol {}
I than created a framework that I want to share with others which includes some classes that extends CommonProtocol and passes CommonProtocol in response to some function calls.
Sharable.framework
public class Sharable : CommonProtocol {
func getCommon() -> CommonProtocol
}
Unfortunately when I attempt to use Sharable.framework in a Project I get there error:
Swift Compiler ErrorUse of undeclared type 'CommonProtocol'
Does anyone know how to make the protocol visible to Modules that use the Sharable.framework?
I am copying the frame Common.framework in the Copy Files step to Destination Frameworks (there was no noticeable change when I made it Shared Frameworks)
If possible I would prefer to only make certain protocols from Common.framework visible through Sharable.framework and I don't want to force my users to import multiple frameworks if I can avoid it.

Include C Library in iOS project

I am working on a project in iOS using Xcode. I want to include a library written in C. But I don't know how to use C library in Objective-C.
Here is the link of Library: https://github.com/bcl/aisparser
Can someone help me?
You're going to hit one obstacle in the form of what's called "name mangling". C++ stores function names in a way not compatible with Obj-C.
Objective-C doesn't implement classes in the same way as C++, so it's not going to like it.
One way around this is to implement a set of simple C functions which call the C++ functions. It'll be a good challenge to keep the number of C functions as low as possible! You'll end up with a nice compact interface! :)
To declare these functions in a C++ file, you'll need to mark them as C with:
extern "C" int function_name(char *blob,int number, double foo) {...}
This disables the standard name-mangling.
Build a header file with the prototypes for all these functions that you can share with your objective C code.
You won't be able to pass classes around in the same way (because your ObjC code can't use them), but you'll be able to pass pointers (although you might have to lie about the types a little).

Resources