Swift Control access per targets - ios

Does any one know how to have different swift control access for different targets. Basically I have an iOS framework in swift with two targets A and B. I wanted a class say "Hello" as public in target A and internal in target B. One of the way to have this define a Swift flag and have something like this.
#if FLAG
public class Hello {
#else
class Hello {
#endif
Open brace with no closing brace in the same scope does compile in swift. One of the possible way to have the empty class under flag and put the rest in an extension. This is not a good solution since I need to make some of the functions also under flag to control the access. Is there any solution to control the access without duplicating the functions ?
Or is the approach fundamentally wrong ? I need to have a wrapper for the class to make it public ?

Unfortunately, this isn't something you can do in Swift. In Objective-C you could do tricks like this and the compiler would ignore anything that wasn't valid inside the macros that weren't excluded. This is not the case for Swift. The entire file must be valid, including parts that are being ignored because of the #if's

Related

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.

Prefix extension functions

In Swift it's not necessary to prefix classes anymore as their module acts as the namespace.
What about prefixing extension functions? For example:
extension UIImage {
public func hnk_hasAlpha() -> Bool { ... }
}
On one hand Swift is not dynamic so collisions would generate compiler errors.
But what happens if compiled code runs in a future iOS/OS X version in which one of my extension methods is added? Would methods in different modules be considered different symbols even if they have the same signature?
Does it make a difference if the extended class is a NSObject subclass or a pure Swift class?
There's some subtlety here:
Extensions of Objective-C types are implemented as Objective-C categories, with all that implies.
Extensions of Swift types, however, are only in effect where visible due to imports. This means that you can't accidentally stomp on a private system method (whether now or one introduced in the future), and if the system introduces a public method with the same name as yours, you'll get a compile-time failure when you rebuild, but your existing app won't break.
You should check those threads also:
Name collisions for extension methods from different frameworks - quote from thread:
regardless the application code imports which Framework, it seems, the actual called implementation depends on the order in Linked Frameworks and Libraries in "First come, first served" manner. But, as far as I know, this behavior is not guaranteed.
and Swift Extension: same extension function in two Modules which also confirms the same problem.
So based on that for Objective-C objects such as UIImage from your example name collisions are possible and you might see unexpected behaviour if there will be two methods with the same name in two different extensions for Objective-C object.

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).

"Redefenition of 'Category' as a different kind of symbol" and conflict with Objc runtime class names

I have got a class in Objective-C:
#interface Category : NSObject
{
// ...
}
All was good and I've used this class with no problems in 3 different projects.
Once I decided to create test target for one project. Then the strange thing occurred: compiler refuses to compile with this error:
Redefenition of 'Category' as a different kind of symbol
it also pointed to runtime.h with
typedef struct objc_category *Category;
Well, it is reasonable.
However, I can not understand why it allowed me to use this class before and what is the difference between original target and test target. I've checked Deploy target, iOS SDK, all macros, header paths, #import <objc/runtime.h> and classes in both targets - these are almost the same.
I don't want to refactor this class's name because of using it in multiples projects, so what can be the reason for such a behavior?
You should refactor the name of this class anyway, to avoid such collisions in the future.
And it will be less painful to do it sooner rather than later.
It is probable that you import a file that imports <objc/runtime.h> at some point.
As the matter of what the difference is between the test target and the regular target, on Xcode testing works by injecting the symbols onto a bundle. There might be some differences in code stripping and symbols visibility that could explain this kind of error.
No wonder Apple recommends to prefix classes with 2 or 3 letters
Although you should do what #Olotiar says in his answer, there's a quick fix.
Go to your project Build Settings, search for "Enable Modules (C and Objective-C)" and set the value to NO.

iOS: how to develop for different targets

I've got an Xcode project with three different targets (say soccer, baseball, basketball) resulting in three different apps. Most of the code is the same, but sometimes it's target-specific.
What's the best way to implement methods which are specific to a target? I'd like to avoid
if ([AppDelegate isSoccerTarget] {
...
} else if () {
...
} else if () {
...
}
I was thinking about using categories which only exist in one of the three targets, but then I can't use a default implementation. And I'd like to avoid inheritance as some classes are already in a class hierarchy and I'd like to keep that simple (avoid person => player, manager resulting in soccerPlayer, basketballPlayer etc.).
What's your way of doing this?
The way I handle it is I place anything that is similar in a super class that is added to all targets, and then I create a new class (for your example "Player") that is different for each target.
So in the source directory I would have subdirectories and files:
basketball/Player.m
baseball/Player.m
...
And then I would select the "Target Membership" for basketball/Player.m to be the "Basketball" target.
This way I only have to instantiate a Player class once and depending on what my target is, it will automatically create the proper class. Hope this helps.
You would make your targets in the Xcode project pane (the file at the very top), and then, in one of the tabs in each target (I forget which one) add some values in the preprocessor macros (might be pre compiler macros). Then, in your code, you can do this: say your preprocessor macro for the baseball target was called BASEBALL and soccer was SOCCER. Your code would look like this:
...blablablaothercode...
#ifdef BASEBALL
NSLog(#"Baseball!");
#endif
#ifdef SOCCER
NSLog(#"Soccer!");
#endif
...blablablaothercode...
These can be used anywhere normal code could be used. Think of it as a 'switch' statement that the compiler can use to see what code to use for each target.

Resources