Include libraries in iOS library project - ios

I am writing an iOS library which depends on some other open-source libraries. Apparently it is not possible to have two classes with the same name, so it is possible that the library compiles, and a project that potentially could use it compiles as well, but they do not work well together (at the linking phase).
The library is targeted at a large audience, so I can not make any assumptions on whether these developers will be importing the same libraries or not, or if they might be using a different, incompatible version of the same libraries.
I have been looking around but couldn't find any clear solution to my problem (maybe there isn't). So far I am thinking of these options:
Inform the users that X libraries are already included in the project, so they do not include them as well. This means they can not use a different version of X libraries.
As a refined version of the first one, use CocoaPods, so dependencies are resolved automatically. Still has the disadvantage that two versions of the library can not coexist.
Import and rename all classes my library depends on, prefixing them, so the names don't conflict with the original ones. This is tedious work, but more importantly, has the disadvantage that I would not be able to pull/push code from/to the original library, as the code would change too much. Still seems to me the best option from the user perspective.
Can you think of a better idea? I'm pretty new to library projects, so maybe there is something obvious I am missing.
We're still not decided whether to distribute in binary or source code form. If there is a reason to choose one or another I would also like to hear your opinion.

When I was faced with this problem I choose your third option and prefixed the dependent classes within my library. The reason you might want to consider doing this rather than relying on the user to import the others would be that you can guarantee compatibility and you don't have to worry about versions of who you depend on.

First point -
Inform the users that X libraries are already included in the project,
so they do not include them as well
so you have a static library Foolib.a, it has a 3rd party dependency Barlib.a, in order for Foolib to build, Foolib's HEADER_SEARCH_PATHS must be set to the path of Barlib's public headers. No more.
If you are distributing your source code you can use CocoaPods (this is a good way to go), or you can add Barlib's repository as a git submodule (or whatever for your choice of VCS) of your repository and hard code the HEADER_SEARCH_PATHS to that path, or you can require that your user grabs their own Barlib and manually edits HEADER_SEARCH_PATHS to the correct path (if you go the CocoaPods or submodule route the user can easily do this as well, so has more options).
Nothing from Barlib is 'in' your project.
On the other hand, if you are distributing a binary for your user to link into their app you must specify in your instructions that Foolib requires Barlib to be linked into the app. Instructions for how to get hold of Barlib would be nice.
Nothing from Barlib is 'in' your project or compiled into your library.
Second Point -
use CocoaPods, so dependencies are resolved automatically. Still has
the disadvantage that two versions of the library can not coexist
Two versions of the same library in one App is impossible, but the situation where the end user already requires Barlib 3.0, wants to use your Foolib, but Foolib requires Barlib 4.0 doesn't have to ever arise - It is up to you the developer. You can be generous and support multiple versions of Barlib (i.e. all Foolib needs to work is a Barlib1.0, Barlib2.0, Barlib3.0 OR Barlib4.0 linked into the app - similar to writing an app that supports iOS5 and iOS6) or, you can be opinionated and require a specific version, and if the user is already requiring a different version of Barlib, tough luck, they will have to change their code if they want to use your library.
Third point -
Import and rename all classes my library depends on, prefixing them,
so the names don't conflict with the original one
This is just too terrible for me to consider at the moment. Sorry.
Nothing from Barlib is ever 'in' your project or compiled into your library. You don't distribute any copy of Barlib - either linked into your binary or as source code.

Related

Framework using library crash

I have 2 frameworks created by me that use (both of them) a library also created by me.
The first framework initialize the library and makes all its workflow. After finishing the first framework, the second one must start.
But when the second one is going to start, after initializing the library, the app using both frameworks crashes with a exc_bad_access error.
Apparently the library is created correctly, but if i comment the line of code to initialize the library in the second framework, the workflow continues (it crashes later because it has no library initialization).
Is there anything I'm doing wrong? Should I use two separate libraries instead?
EDIT:
Imagine the situation:
Framework A has this methods: start, stop. And while it works it delegate to the methods: infoFromA,frameworkAFinished.
Framework B has this methods: start, stop. And while it works it delegate to the methods: infoFromB,frameworkBFinished.
Both start methods initialize the static library mentioned (lets call it problematicLibrary).
Both frameworks present some views to make its functionality. So lets make an example of the app workflow.
At the app view viewWillAppear method, I start the Framework A just using:
[FrameworkA start]; , this will initialize the library and present a view. With this view (using my problematicLibrary) some info will be delegated to the infoFromA delegated method. And after all the info is delegated, it will delegate to frameworkAFinished.
When the FrameworkA has delegated to the frameworkAFinished I start the next Framework: [FrameworkB start]. As the other Framework, it will initialize the library and present a view. While debugging, all the initialization of the library is done (create the instances of the needed objects and a new instance of the library is created) and while its presenting the view it goes through the viewDidLoad method and then it throws an exc_bad_access error at the problematicLibrary initialization line (which has been done before and continued to present the view!!) without going into any other method from the view.
I have checked if the initialization is doing well, and all the variables were at null value before the initialization, and a new memory address is given to the library object.
This sounds strongly like a symbol conflict to me. I'm just surprised the linker didn't catch it, but I assume that's because you're using a static library in both your frameworks instead of simply yet another framework.
Generally speaking, I'd warn that "this is a bad idea™". What you're trying to introduce into your design is basically dependency management. Like a lot of blog articles and specifically this SO answer suggest, you should avoid packaging frameworks (and by extension libraries) into frameworks.
What most likely happens in your scenario is this (I admit I'm guessing a bit here): You linked the library into Framework A. Thus, the library becomes a fixed part of it. Its symbols are in it, even if you did not expose them to the app in any header files or the like. As long as you use only that, everything works smoothly. Then comes Framework B, of which the library is also a fixed part. Even though you can't see it from your app, the very same symbols are inside it. This, however, clashes with the symbols that were already loaded by Framework A, hence a crash (as said, this would usually be caught by the linker, but I guess you "tricked" it by building the frameworks beforehand and packaged the library in them). Maybe somebody else can explain this in more detail, but that quickly becomes besides the point as to how you would go for a solution. From how I see it, it just won't work this way.
So here's a suggestion for how you can solve your problem:
If you really, really need to split like this (two frameworks used in your app using the same dependency), I'd suggest removing the library from the frameworks (i.e. make them depend on it, but not package the actual .a file in them) and documenting that properly. Then add the library to your app project, just like you added the frameworks.
If you want to make this fancy and easily installable into other apps, I'd recommend setting up a private CocoaPods repository and turn your frameworks into private pods. You can then easily define the library (or rather "new Framework C") as a dependency for Framework A and Framework B. When you then pod install in your app, cocoapods figures out the dependency and adds Framework C automatically to your project. This scenario is exactly what cocoapods (or any dependency manager for that matter) was designed for. It automates and helps in the project setup, so that the final build (the app) doesn't have to figure out dynamically what it can and can't use. The end result is the same.
Trying to duplicate that "in code" quickly becomes messy. Frameworks trying to figure out things of the surrounding app/project that uses them (like "is my dependency so-and-so already linked? if not, can I load my own version of the library?") can lead to a lot of pain.
Okay, in response to your comment I'll try my hand at a more detailed How-To for the non-cocoapods setup. As a preface, though, let me say that that's kinda hard to do on top of my head, as I have no ready sample project to toy around with. Since this is one of those "set it up once and then forget aout it for a long time" I have to admit my recollection of these things is a bit fuzzy, so consider this as a sort of "rough direction". There might be things you need to configure differently than how I recall them. Other SO user are thus hereby invited to edit and correct my answer here, too. :)
First, I have to say I am not exactly sure whether you need to convert your static library into a framework or not for this, I think you don't so I'll go from here (I have never used a static library in that way).
That means you can leave the project that builds your library as is. On second thought, you probably have to do this to be able to link against the library without making it a part of the framework that uses it. I will still refer to this code as "library" in the below points, but assume that you're able to turn it into a dynamic framework as well.
The projects building Framework A and Framework B should be changed. I don't know how you have this set up (as one project with various targets, whether you have a "development application" as part of it to test the frameworks on themselves, etc.), but the important thing is that in the target that builds a framework, the library should be linked (i.e. in the "Link Binary With Libraries" build phase), but not copied (i.e. it must not be in the "Copy Bundle Ressources" build phase). It might be tricky to set up any development/test target you use to run, depending on how you did that so far. For example you might have to manually edit Library Search paths in your build settings to be able to properly compile the framework.
Lastly, you need to change your final app's project settings, obviously. The library that was originally part of Framework A and B now needs to be linked to from its project directly, and, obviously, it needs to be copied into the bundle as well. Note that any projects that include either of your frameworks (A or B or both) in the future must do so, otherwise they won't work, because these frameworks expect the library to be present (but no longer "bring it with them").
In spite of this long-ish text wall, it shouldn't be that complicated, I think, but you may still want to check out how cocoapods can support you with something like this, perhaps it's helpful in the future. The linked article expects basic knowledge on how to use a pod and write one, but the other guides on the site explain that pretty well. I am just saying this because in the end, when using cocoapods in a project to add multiple libraries/frameworks that introduce dependencies, it basically sets up your project in the way I described above. It uses some fancy shell scripts that ensure everything is copied to the correct folders and such, but overall speaking that's how it works: A pod's podspec tells cocoapods what additional pods to include in your app for it to work (a dependecy the pod expects to be there, but doesn't "bring in" by itself).
Check if they are both compiling for the same target.
Check if they have access to the same target membership.
Check build phases to see that they are both there.
I think because the first library is not 'well' referencing the second one.
Also i think that you can't import a framework inside another one.
To make things easier, you can merge the two frameworks on a single one.
Also you can add a callback (using protocols or closures) that informs for the end of the first workflow, and you use this callback to initialize the second framework. This way the initialization will not be made automatically.

Why we have to use dependency manager?

I am developing an app for IOS,and I have to use some framework.
as you know Cocoa pods and Carthage are dependancy manager for iOS and mac OS
my question is "why we have to use dependancy manager?, instead of using dependancy manager just clone that project[was written by other programmer and can be used as framework] and drag and drop to your project ??"
Thanks for your answers
Few things that you need to think about is:
Updating your dependencies when new versions came out.
Updating dependencies for multiple platforms.
Interdependent frameworks and different framework versions for dependant frameworks.
Basically, time that you will spend on maintaining dependancies for your project will grow as your project grows. Dependancy managers allow you to avoid all this unnecessary and boring work.
There are a lot of other reasons to use DM instead of just importing frameworks. More about you can find here. And here.
At some point you might want to use 3rd party code to get extra features or something, you can copy the source code but how you will update it in the future? keep coping it again!!
Also some of your 3rd party code might depend on other 3rd part code, and if you copied it twice, you will get duplicate symbols.
Dependency managers handle all this for you.
My advice is to use Carthage or submodules, but do not use CocoPods, anything that touches the project file is not a good practice with Apple.
Why Libraries are Your Friend
While you aren’t strictly required to use third-party libraries or
frameworks, they can definitely save you a lot of time and let you
focus on polishing your app instead of typing out countless lines of
code that you simply don’t need to write.
You can use third-party frameworks and libraries without a dependency
manager too, and you can get hands-on tutorials about them right here
on this site. For example, there’s our Alamofire tutorial, and our
SwiftyJSON tutorial.
Without a dependency manager, you simply add each library’s code to
your project manually. However, this approach has several
disadvantages:
Updating a library to a new version can be difficult, especially if several libraries must be updated together because one depends on
another.
Including a library in your project makes it tempting to make local changes to the code, making it harder to update to a newer version
later.
Determining the current versions of libraries used in your app can be hard to do, especially if you don’t proactively keep track of them.
Finding new libraries can be difficult without a central location to see all the available libraries.
CocoaPods helps you overcome all of these issues and more. It fetches library code, resolves dependencies between libraries, helps
you search for and discover new libraries, and even sets up the right
environment to build your project with minimum hassle.
Courtesy
https://www.raywenderlich.com/97014/use-cocoapods-with-swift

Multiple frameworks and common library

Using iOS 8, Xcode 6.
Let's say I have 2 dynamic frameworks, frameworkA and frameworkB and they are both dependent on libC. In addition, I have an app that uses both frameworkA and frameworkB. My original thought was to make frameworkA and frameworkB umbrella frameworks and libC a subframework. However, Apple advises against umbrella framework and this post describes why umbrella framework is a bad idea due to potential linker conflict issue.
My second option is to use cocoapods (still new to this so a bit fuzzy on details) to use libC as a pod which then gets compiled into frameworkA and frameworkB. However, it occurred to me that both frameworks still has its own copy of the libC. Since the app uses both frameworks, will this result in a linker conflict issue as well? Is there a better way to solve this problem?
UPDATE
#Rob The projects I work on do require complex dependency management but I kept the problem domain simple in the question to try to better understand how and if using cocoapods can help solve the linker conflict issue with umbrella frameworks. I work with a team of developers who write libraries and can depend on each other's base libraries that provide versioned common APIs. We are required to package and deliver as few libraries as possible to a different organization that is building an app with our libraries and one of their key requirement is that we deliver a dynamic framework.
The best way to solve most problems is to put all the code in a project and compile it. When you have specialized problems that make that problematic, then you should look at other solutions, such as static libraries, and finally frameworks.
Static libraries can make sense if you have a code base that has pieces which require different build requirements. If all the pieces have the same build settings, then just "add files" them into your project from a "common" directory and build your project. Static libraries can be attractive if your build times are very significant and some pieces never change and you want to be able to "clean" without rebuilding those parts. But wait until you start having that problem before you go making complicated multi-package projects.
If you sell closed-source libraries, then frameworks are very attractive. You should strongly avoid adding third-party dependencies for the reasons you note. If you must, the best way is to help your customers package all the pieces as frameworks and have them link everything at the end. But that adds a lot of annoyance; so make sure you really need that third-party piece.
You might also consider frameworks if you have a very large piece of reusable code that has its own lifecycle separate from the main products. But again, keep it simple. Avoid third party stuff inside of it, and if you must have third party stuff, then have the consumers link it at the end.
(This isn't a new solution, BTW. When you use curl, if you want SSL, you need to also download and build OpenSSL and link them together yourself. Curl doesn't come with OpenSSL built in.)
But in the vast majority of cases, this is all overkill. Don't jump to frameworks. Don't jump to libraries. Just put all the code in the project and compile it. 90% of your problems will evaporate. iOS projects in particular just aren't that big usually. What problem is a framework solving?
If you have a lot of code that your organization uses repeatedly in lots of products, then I have heard many teams have good luck using internal CocoaPods to manage that. But that's just to simplify checking the code out. It still all goes into a project and you compile it together into one binary; no frameworks needed. Dynamic frameworks are a nice feature in for certain kinds of problems that were really painful before. But, for most situations, they're just complexity looking for a problem.
(If you have one of those specialized problems, edit your question and I'm happy to discuss further how you might approach it.)
EDIT: (You fall into that "specialized problem," so let's talk about it. I did, too, for many years inside of a large multi-team Mac and iOS dev environment. And we tried just about every different solution, including Frameworks. They're only new on iOS.)
Within an org like you describe, I would strongly recommend packaging each dependency as its own framework (AFNetworking, JSONKit, etc) and each of your pieces as a framework, and then have the app devs link all of them together at the end. In this way, it is identical to other dynamic libraries (libcurl, openssl, etc.) which require the app dev to link everything together.
In no case should dynamic frameworks include other frameworks that could otherwise be required (i.e. frameworks should never package "third party" stuff). That will explode. You cannot make that not explode. You'll either have bloat, build conflicts, or runtime conflicts. It's like merge conflicts. There's a point at which a developer has to make a choice. App-level linking is making that choice.
Making components over-dependent on other components is the source of decades of trouble, from Windows DLL Hell to iOS apps with competing crash handlers. All the best component systems look like Legos, where the end user assembles small pieces that have minimal dependencies. As much as possible, make your internal frameworks rely on nothing but Cocoa. This has some tangible design influences:
Avoid directly requiring logging or analytic engines. Provide a delegate interface that can be adapted to the engines of the caller.
Avoid trivial categories (methods that save just a few lines of code). Just write the code directly.
Avoid adding framework dependencies that aren't buying you a lot. Don't add AFNetworking just to save a few lines of code over NSURLConnection. Of course if you're heavily relying on the features of another framework, that's different. But as a framework developer your threshold should be quite high before requiring another framework.
Strongly avoid being clever in the build or version control. I've seen too many cases where people want to make everything "automatic" for the app-level developer, and so make the system really complicated. Just say "you need to link this and import this and put this in your app delegate startup." Don't create complicated build and version control systems to save 2 minutes on the first build or two lines of initialization logic. These things blow up and waste hours to work around. Don't get clever with +load magic. Just make it clear and consistent.
And of course, good luck. Supporting other devs is always an interesting challenge.

Use two versions of the same library

I'm working in a iOS project that includes a static library created by another company.
The library include an old version of AFNeworking and I don't have any source files.
Now i need to use a more recent (and less bugged) version of afneworking, but i cannot include the same class twice in the project (of course) because all the "duplicate symbols".
I understand that it's impossible replacing the version included in the library, but how can i include another version along the old one?
There is a (easy) way to refactor the entire framework before include in my project?
thanks
You'll have to repackage the static library to remove the embedded AFNetworking files.
Unpack the library with:
$ ar x libwhatever.a
And re-package it, including all files except the AFNetworking object files:
$ ar cr libwhatever.a file1.o ... fileN.o
You will then have to link your executable with the new AFNetworking static library and hope that there haven't been API changes which will break the code in libwhatever.a. If there are then I doubt there is much you can do.
I'm afraid this isn't easy to do. Very few environments allow you to link against two separate versions of the same framework at the same time, and Xcode / iOS is not one of them.
As I see it, you have three options:
1) Link against their library and use the same version of AFNetworking they use.
2) Link against their library, and manually load the newer version of AFNetworking and pull symbols from it. Be warned: this will get ugly fast and future maintainers will wonder what you were smoking.
3) Get them to update their library.
On a side note, I don't know the circumstances here, but in general they should be providing you with sources. It's a very backwards practice to provide only a static (static!) library and no way to know what it's doing inside. You'll have to sign a software license agreement and whatnot to protect their interests.
The best and most proper way of handling this would be to contact the the creator of the static library and get them to resolve the situation. They could resolve it either by updating the embedded version of AFNetworking, removing their dependence on AFNetworking, or adding a prefix for their embedded copy of AFNetworking. The last one is probably a good idea anyway when a third party library embeds a different library, because otherwise it would be impossible to use two libraries simultaneously that both include the same third party library.
You could also refactor the copy of AFNetworking that you include yourself to change the names of classes to have a prefix, although this should be unnecessary, as the static library vendor should have done this themselves already.
Lastly, you could find a different library that accomplishes the same thing as your current one but that doesn't embed AFNetworking.

iOS SDKs: Renaming a lot of classes

I'm developing an iOS SDK that integrates other SDKs (Facebook SDK 3.5, for example).
To prevent collisions and allow my customers to import those SDKs as well, I want to rename all of the classes/enums in my code (for example, rename FBSession to RDFBSession, etc).
Is there an easy way to do this instead of going class-by-class and using Xcode's rename feature?
Apple provide a command-line tool called tops(1) that is designed for scripting large-scale code refactoring (renaming C functions, Objective-C methods, classes, and other tokens):
tops -verbose replace "FBSession" with "RDFBSession" Sources/*.[hm]
If you have a lot of replacements, you can put all of the replace... commands into a file that you pass with the -scriptfile option. The man page has more information on the more complex commands/options (and examples).
Xcode also offers textual Search and Replace. This will be faster than individual refactors, but it is ultimately less automated. You can make the step by step refactoring faster by first minimizing the project to the relevant dependencies/sources (if possible).
However, renaming the declarations in a library will not alter the symbol names of its associated binary. If it is distributed with a binary, then renaming will just result in linker errors or (in some cases) runtime errors.
The best idea if you need to use a 3rd party library which your clients might also use is to simply inform them they need to link the library with their app, then publish the version(s) the current release supports so they know they have some extra testing if they go too far ahead with some libraries.
I think that a better approach than simply renaming your classes would be to download Facebook's open source code, rename the classes there and compile a new static library with a set of renamed header files. Then you can be sure that no collisions occur and that you're using symbols that you named yourself.
I must warn you though - working like this may make updating the SDK a nightmare regardless of how you tackle this specific issue.

Resources