Linker error, but only on test files - ios

Here's a screen capture of my app. I'm using UIKit to create a PDF from some of the app data. I get no errors on the app itself but in the test section I get a bunch of them that look like the app can't find some CoreGraphics references. But CG is being imported in Tests.h... I can run the app, on simulator and device with no problems. Any idea what is causing this?
To add a little more to this: I imported the class where I am making the PDF into another application and I am not getting the errors there, so that's good. So any ideas what could be happening? (And yes, the libraries are in my app)

It is being imported but not linked. You need to link the CoreGraphics framework:
Importing a class header A into class B allows class B to know what public API (variables, properties and methods) in class A can be used by other classes and that is why you do not get any errors until you compile.
When you compile, you need the actual code (.m file if you will) to be able to execute the calls that class B is doing to class A variables, properties and methods. That code resides in the libraries/ frameworks you link to your project. Your code with the linked libraries together become the final compiled code.
Here is what you need to do:
Single click on your project (top left of the navigator)
Select your Target project
Click on the "Build Phases" tab
Click on "Link Binary with Libraries"
Add CoreGraphics.framework
That should solve it.

I solved it. I removed the libraries, reinstalled them and did a clean and that seemed to fix the issue.

Related

Importing a library in to an Xcode 7 project

So I am trying to add a static library to my project in order to interface with a scanner. I have linked the binary in build phases to the libCaptuvoSDK.a, put the Captuvo.h header file in the project folder, and finally set the project to always search the user paths and added $(BUILT_PRODUCTS_DIR) recursive to the user header search paths. After doing all this I am trying to use #import "Captuvo.h" in my ViewController.swift file and getting the 2 errors Expected identifier in import declaration, and Expected expression. I have tried different combinations of importing and none of them seem to make a difference so I am led to believe the issue is with my process of adding the library.
I am new to Xcode and have never used a third party library in an application before so I feel I may be making a simple mistake or just misinterpreting things. Any help is appreciated!
Okay so I managed to fix my issue! I had imported the static library properly but the real issue was the header file. I fixed my issue by creating a new file in my projects folder named Quick-Scan-Bridging-Header.h. Inside that file is where the #import "Captuvo.h" line belonged. Once that was done I opened the Quick Scan apps build settings and under Objective-C Bridging Header I added the path Quick Scan/Quick-Scan-Bridging-Header. I also added the Header Search Path $(BUILT_PRODUCTS_DIR)
After I did all this I am able to use the Captuvo classes in my ViewController.swift file.

Don't we need to link framework to XCode project anymore?

Base on this question
Why don't iOS framework dependencies need to be explicitly linked to a static library
I read the selected answer and still don't understand so I made an example project
Test Project on Github
In the test project, I remove all framework from Link Binary With Libraries and File navigation for both main project and the static library (including Foundation.framework and UIKit.framework too), basically, both project link to 0 frameworks.
Questions are
In static library, it's including MapKit/MapKit.h without referencing the Mapkit.framework to the project, why is its still working?
In main project, I remove UIKit.framework and Foundation.framework from the project, why is it still working?
Since it's working for now, will there be any issue later?
Thank you for your comment.
P.S. By working, I mean I can run on the simulator and I can archive the main project without any error.
Edit 25/07/2014
I tried with the real app that I'm working on, it's the same.
I highlight Foundation, UIKit, CoreData and 10 another frameworks in File Navigation, well, all of them.
Uncheck the target in Utilities Panel --> Target Membership
Build : Pass, Run : Pass
Every functionality of my app is still working as expected. I don't get this.
Check your project build settings. Underneath LLVM 5.1 — Language — Modules you should see the option 'Link Frameworks Automatically'. In your case it sounds like it's set to 'YES', the default.
In that case, instead of producing an error when you reference a class that the compiler doesn't know, it'll figure out which Framework contains that class and link it. In your code it'll be MKMapView or one of the other MapKit classes that triggers the linkage.
EDIT: from the relevant 'What's New?' document:
Auto Linking is enabled for frameworks imported by code modules. When
a source file includes a header from a framework that supports
modules, the compiler generates extra information in the object file
to automatically link in that framework. The result is that, in most
cases, you will not need to specify a separate list of the frameworks
to link with your target when you use a framework API that supports
modules.
Another way of looking at it is that the compiler is smart enough to mutate #import to #import when the framework has been built appropriately. All system frameworks have been.
To elaborate #Tommy's answer, a framework that supports modules satisfies the following 2 conditions:
Under Build Settings > Packaging
Define Modules is set to YES
Module Map File exists.
So, if you're certain that the framework you're using in your code modularizes like that, you can choose to not explicitly add it in the link phase as it will be automatically added as long as in the project file, under Apple Clang - Language - Modules, The option Link Frameworks Automatically is set to YES.

How to use a static library (e.g. cocoapods library) on a XCTest?

I'm working with Core Data and, as I the model gets more complex, I need to make sure that the new changes I introduce don't break my model unexpectedly in other parts.
I can create unit tests and run them every time I change something on my model. If something breaks, there might be something wrong with my model or at least I know I have to modify some queries in the main code/tests.
I'm using MagicalRecord to have access to some convenience methods.
I also use cocoapods for the same reason, convenience.
The problem is that cocoapods creates a static library and links it against my target, but in Xcode, new test targets are not automatically configured to link against the same libraries/frameworks the target in question links against to.
How can I have a XCTest link against a static library?
This is not only helpful with MagicalRecord/Core Data, but when you're using an external library it's a good idea to have tests to make sure that updates on the library don't break your App.
If you're using cocoapods, you can simply use link_with to include your test target, but if you're using a static library not created by cocoapods you can do the following:
(I will still use a cocoapods library for the instructions, as that's what I'm working with, but the idea is the same if you're not using a cocoapods library)
Once you have created a new Test Target, click on the project root node in the project navigator and select your test target.
Go to Build Settings and search for Header Search Paths. Double click on the Header Search Paths item and enter
${SRCROOT}/Pods/Headers and select recursive if you want to import all of your cocoapods libraries headers or enter them individually:
${SRCROOT}/Pods/Headers/MagicalRecord leaving non-recursive selected (although in this case it doesn't really matter).
Now search for Linking and in Other Linker Flags add -ObjC
Now with your Test Target still selected, go to Build Phases and in Link Binary With Libraries click on the + and add libPods.a or the other libraries individually (libPods-MagicalRecord.a)
You should be able to run a XCTest using the static library.
Optional: I like to import the headers I know I'm going to use in the -Prefix.pch file. You can go to your target test group in the Project Navigator. Go to the Supporting Files group and open the -Prefix.pch file. For MagicalRecord I like to add:
#define MR_SHORTHAND
#import "CoreData+MagicalRecord.h"
For more information:
Unit Testing with Core Data
Creating a Static Library in iOS
Tutorial
After a lot of fighting, these steps worked for me:
1) Project> Info
On configurations, set the Test Target to share the same Configuration File as your main project (generated by Cocoapods).
Now, you should start to get some errors because XCUnit framework is missing, but now your external libraries imported with CocoaPod are visible on your test project.
2) On the Test Target>Build Settings look for Header Search Paths, once there add:
$(DEVELOPER_DIR)/Platforms/iPhoneOS.platform/Developer/Library/Frameworks
$(DEVELOPER_DIR)/Platforms/iPhoneSimulator.platform/Developer/Library/Frameworks
The Unit Test framework is inside your Xcode App, this headers will make them public to be added later.
3) On the Test Target> Build Phases add the SenTestingKit.framework
And it should look like this
From there, everything seems to work for me. Good Luck.

iOS static library does not work

I followed the instructions in this article to create a static library:
http://developer.apple.com/library/ios/#technotes/iOSStaticLibraries/Articles/creating.html
I built it for iPhone simulator target. It built successfully, then I imported into a new project where I wanted to use it. It imported fine and there are no problems, but the library doesn't work. There are no library methods that I'm calling; rather the purpose of the library is to swizzle the UIViewController viewDidAppear method so that a piece of code gets executed every time a UIViewController appears. This piece of code is not getting called, despite my library being included in the "Link Binary With Libraries" build phase.
I know the problem isn't with the code itself because if I import the raw .m and .h source files not as a library, everything works fine.
Did your library contain any categories?
If so, I think you should follow these steps to get it work:
In Xcode, double-click the target's name under "Targets" in the Project window.
Choose the Build Settings panel.
Scroll down to the "Other Linker Flags" build setting under the Linking collection and set its value to "-all_load -ObjC".
Please refer to corresponding Apple Documentation
Here is a related question: Objective-C categories in static library

Reference code in a separate project in XCode 4.2

I'm working on an iOS app where I use third party libraries. I want to migrate my project to use ARC, but the third party libraries are still using the old memory management. So I want to separate third party code and put it in a separate project without ARC, and then somehow link that project into my iOS-app project, so that they will be built together using the same configuration.
Is this possible to do in a very simple way, or am i better of just turning off ARC for the individual files? (seems very tedious..)
Can I use a workspace? Where one project is my iOS app and the other just contains third party code?
I've played around a bit and googled a lot, but there just doesn't seem to be any simple soultion, or am I wrong?
So I figured it out myself, with a lot of help from different blogs. Something this basic should be more trivial and well documented... But here we go, this is what I did to get a library for AsiHttpRequest:
Create a new iOS project. Select the 'Cocoa Touch Static Library' template. Call it whatever you like. You don't want to tick 'Use automatic reference counting', since AsiHttpRequest does not support it.
Select a location for your library project (will matter later on).
Delete the default .h- and .m-file created by Xcode.
Drag and drop the AsiHttpRequest files into the project
You can add the frameworks that AsiHttpRequest is dependent of, but you will have to add them to your main project anyway, so it is not necessary.
Try to build the project, it should do so without errors.
Open your main project
From finder, drag your library .proj-file into your main project (in Xcode, so that it 'lands' onto the main project file)
The library project should now appear under your main project (still in XCode). It should be expandable and you should be able to see the library project files as well. If it doesn't, try closing all open projects and reopen the main project.
Select the main project, and select target. Under Build Phases - Link Binary With Libraries, click the +-sign.
In the list of frameworks you should see your library project (called something like libname.a). Select that file
The newly added file might appear red in the list of frameworks, don't worry, it works anyway. Guess it's a bug.
Still under target, go to Build Settings
Under Header Search Paths add the relative search path to where the library .h-files are. This is relative to your main projects .proj-file. (For example ../some folder/libproject/)
Hopefully your main project will build without errors and the library project will be built at the same time, using the same configuration as the main project.
I have no idea if this is a good approach or if there is some easier way to do it. However, I like this, since I can use the library project in several projects. And if I want to update the library project, I only have to do it in one place, and the other projects will be updated as well, since they all reference the same project.
Edit1:
I had some problems with library projects using objective c categories. I received unrecognized selector sent to instance errors in runtime when trying to call those methods. This problem was solved by following the answer given here.
Go to build settings of the target in the main project and add -ObjC to the entry called Other Linker Flags
Edit2:
I found this template for creating Universal frameworks. I haven't tried it, but I guess something like this would work as well.

Resources