8

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.

Ivan
  • 782
  • 11
  • 23

3 Answers3

5

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

Gero
  • 4,394
  • 20
  • 36
  • Hi @Gero, thanks for your time. I think I understood you. So there are like 2 ways, the "ugly" one, and the fancy one. For the ugly one, in which I don't have to package the library and add it to the app. I read to do something like that, but I didn't manage to do it. Do you have any advice to try it again? I have never used CocoaPods, so I will try the "ugly" way and then try to improve it to the fancy one. – Ivan Jul 21 '17 at 06:38
  • I edited my answer with a hot-to, but please keep in mind that the specific project setups in your case have so many possibilities (from my perspective, not knowing your code and config) that I had to stay a little vague. – Gero Jul 21 '17 at 09:34
  • Thank you again for your helpful answers, and sorry for being such a pain in the ass. I have tried what you say, I had the library (.a) already linked at "Linked Binaries with Libraries", the library wasn't at the "Copy bundle Resources". At first I had the library in the same path as the source files, but then I moved it to the Desktop and changed the "Library Search Paths" so it can find it. I made it compile, but keep getting the same. Duplicated implementation and my lovely `exc_bad_access`. – Ivan Jul 21 '17 at 10:12
  • By the way, thanks for the cocoapods guides and advices, I will try them in the future. – Ivan Jul 21 '17 at 10:15
  • Hm... as said, I have limited experience with static libraries, but considering they're "static" it might be that the linker fully includes the symbols in the resulting binary of the framework. Then you'd have to turn your static library into a dynamic framework that is linked to make the whole ordeal work. – Gero Jul 21 '17 at 10:27
  • Just had the time to check a bit online and yup: "Static" means, well, static... I kinda derped there, not thinking about this actually very important prefix. See https://pewpewthespells.com/blog/static_and_dynamic_libraries.html – Gero Jul 21 '17 at 11:49
  • Thank you, I will assume this cannot be done with Static Libraries, and must be done with dynamic?. But as far as I know, apple won't allow to upload an app which contains dynamic libraries/frameworks. Am I right? – Ivan Jul 21 '17 at 11:59
  • First, yes: The library must be dynamic (and while you're at it I suggest to then make a dynamic *framework* out of it). Second: No, using dynamic frameworks is allowed as long as they're part of the signed bundle that is sent to review. During the build and upload process, Xcode automatically signs the included frameworks. What is forbidden is *downloading dynamic frameworks from the net* and opening them in your app (dlopen will throw an error I guess). I'm not sure whether Xcode properly signs dynamic *libraries* automatically or you need to config that, but it would certainly be allowed. – Gero Jul 21 '17 at 12:04
  • Okay, Thank You a lot, I didn't try to make them dynamic for this reason but with that info, I can give a try to make them dynamic. – Ivan Jul 21 '17 at 12:06
  • Have you succeeded in setting up your inter-dependent frameworks/libraries now? If so I'd appreciate if you accepted my answer (assuming it was the one that helped you do so). :) – Gero Jul 25 '17 at 14:49
  • I am still trying to transform my static library into a dynamic one, but still getting some errors. I will give you the bounty for your help, and will accept the answer as soon as I manage to make it work. – Ivan Jul 26 '17 at 06:01
3
  1. Check if they are both compiling for the same target.
  2. Check if they have access to the same target membership.
  3. Check build phases to see that they are both there.
Pedro Pinho
  • 652
  • 3
  • 6
  • When I have imported them to the app using them, i can use both separately. This is, I can launch the first one (lets call it A) and do all its workflow and I can launch the second one (lets call it B) and do the workflow too. I can use A or B independently, but at the time I want to do A and when its finished launch B or B and then A, it crashes – Ivan Jul 19 '17 at 05:12
  • I understand, but do you really need to split them? – Pedro Pinho Jul 19 '17 at 17:29
  • 1
    Yes, I do. I have a big framework with various functionalities, and what I need is to make a framework with each of the functionalities. – Ivan Jul 20 '17 at 05:49
0

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.

Mourad Brahim
  • 531
  • 2
  • 15
  • First of all, thanks for your answer. If my library is not 'well' referencing the second one how can I use the second framework if I use it independently? To your second issue, im not importing a framework inside another one, the frameworks are both imported into an app – Ivan Jul 19 '17 at 10:44
  • In a previous version, both frameworks were just one that use the library. But now I need it to be into two frameworks, and both of them will need the library too. – Ivan Jul 19 '17 at 10:47
  • I understand you needs, but i can't imagine the reason of your problem. Can you post some examples from your code, may be it helps me understanding​ the reason. – Mourad Brahim Jul 19 '17 at 19:28
  • 1
    I added a detailed explained example of use. Let me know if you need something more. – Ivan Jul 20 '17 at 06:14