Class Foo is implemented in both MyApp and MyAppTestCase. One of the two will be used. Which one is undefined - objective-c

Recently I started Unit testing my application. This project (in Xcode4) was created without a unit test bundle so I had to set it up.
I have followed the steps from here: http://cocoawithlove.com/2009/12/sample-mac-application-with-complete.html
And It was working well for simple classes but now I am trying to test a class that depends on another and that on another, etc.
First I got a linker error so I added *.m files to the test case target but now I get a warning for every class I am trying to test:
Class Foo is implemented in both MyApp
and MyAppTestCase. One of the two will
be used. Which one is undefined.
I wonder why is that? How can I solve this? Maybe I missed something when setting the unit test target?
Edit - The Solution
Set "Bundle Loader" correctly to $(BUILT_PRODUCTS_DIR)/AppName.app/AppName
Set "Symbols Hidden by Default" to NO (in Build Settings of the target application). This is where the linker errors come from because it is YES by default!. I've been struggling with this for so long!.
Source: Linking error for unit testing with XCode 4?

Class Foo is implemented in both MyApp and MyAppTestCase. One of the two will be used. Which one is undefined.
I wonder why is that?
because both images (the app and the unit test bundle) define the implementation of the class. the class is dynamically loaded into the objc runtime. the objc runtime uses a flat namespace. how this works:
the binary is loaded, starting with its dependencies
as each binary is loaded, the objc classes register with the objc runtime
if a class with a specific name is loaded twice, the behaviour is undefined. one implementation of a class (with identical names) can be loaded into the objc runtime.
the typical problem here is that you will be returned one implementation - your app will likely crash when the type conflicts (when the class does not come from the same source file).
you typically avoid this by either renaming a class, or export the class in one image. renaming the class obviously does not apply to your case. you have one file Foo.m which is being compiled, exported, and loaded by two images when it should be in one.
this should be interpreted by you as a duplicate symbol linker error. even though the implementation is the same source file (and the implementation is the same) - this a problem that you must fix.
How can I solve this?
if Foo.m is a class of the app, you have to remove (do not compile and link) Foo.m from the unit test. if it's part of the unit test, then do not compile and link it into the unit test target.
then, follow the instructions in the post for linking/loading your unit test to the app. it's in this general area of the post: where "WhereIsMyMac" is the name of the application you're unit testing. This will let the testing target link against the application (so you don't get linker errors when compiling). the important part is that your test files are compiled in the unit test target (only), and your app's classes are compiled and linked into the app. you can't just add them - they link and load dynamically.
Maybe I missed something when setting the unit test target?
From the article you linked:
Note: The testing target is a separate target. This means that you need to be careful of target membership. All application source files should be added to the application target only. Test code files should be added to the testing target only.
the part that you got wrong is probably the link and load phases of the unit test bundle.

If you are using Cocoapods, your podfile only needs the dependencies in the section for the main target, not the test targets. If you do add duplicate dependencies for the test targets, you'll get the OP's error message.
target 'MyProject' do
pod 'Parse'
end
target 'MyProjectTests' do
end
target 'MyProjectUITests' do
end

For me, all I needed to do was uncheck the checkbox that makes the Foo class a member of the unit test target. It should not be a member of both targets, and should look like this:
In case you can't see the image, it's a screenshot of the Xcode "Target Membership" pane. There are two targets: one with an "A" application icon and the test name. The other is the unit test target, and has a unit test icon:
Target Membership
[X] Foo
[ ] FooTests

For me this happened because I deployed to the device and then to the simulator as I have NSZombies enabled. The solution was to switch to the simulator configuration & do a Product -> Clean then switch to the device configuration & do the same. Error went away. It's to do with build cache.

The reason is that you override RUNPATH_SEARCH_PATHS of your App Target`s build setting defined in other target.
Solution:
Go to your App Target and find RUNPATH_SEARCH_PATHS build setting and use there $(inherited) flag for both: Debug and Release

Come across the same issues, My situation is Class NSNotification is implemented in both /System/Library/Frameworks/Foundation.framework/Foundation, is there any dude come across the same issue, any direction or advise will be appriciated.

Related

Compile-time warning about missing category method implementation

In our Xcode project we have multiple targets which share some common code. Each target includes only sources which are actually used by it. So when we use some category methods inside classes which are shared between targets we need to make sure that this category implementation is also included in all targets. Xcode doesn't show any warnings during compile time or link time if we forget to include category implementation to some of the targets. And it is troublesome to do it by hand.
Is there any automated way to ensure that category implementations are included to the targets which use them?
Categories are not automatically linked to the final binary.
They are linked if the linker finds the file where they are defined is used (which was a source of constant bug some times ago).
What you can do is use a special flag on the linker: '-all_load' and '-ObjC' in Build Settings/Linking/Other Linker flags
-ObjC Loads all members of static archive libraries that implement an Objective-C class or category.
And from this discussion:
-all_load and -force_load tell the linker to link the entire static archive in the final executable, even if the linker thinks that parts
of the archive are unused.
Another way I use to force link the module is to put a C function in the file:
void _linkWithNBLogClass(void)
{
NSLog(#"%s", __FUNCTION__);
}
and call it at the start of my application:
linkWithNBLogClass();
This way, by the console feedback, I'm sure my module is loaded and ready to be used.
The described behavior is as intended and much existing code would break, if it is changed.
Prior to formal protocols there was a need to declare methods without defining them. This was for optional methods, i. e. for declaring a delegate API. The usual technique was to declare a so-called informal protocol, consisting of a category on NSObject that is never implemented.
But if you have a category implementation, of course the completeness of it is checked against the category interface. (Otherwise you get a "Method definition for X is not found" error.) So you do not have a missing method in the category implementation, but a missing category implementation.
I do not think that this is a big deal. You will get a runtime error instead of a compile time error and simply add the category implementation to the target.

Warnings while using a plugin and static library in a cocoa project

I have a scenario where I need to use a plugin as well as a static library into my xcode project. The plugin will be dynamically loaded into the system. Now, the static library is also getting used in creation of the plugin.
While executing my project I am getting a warning saying :
Class A is getting referenced from /staticLibraryPath and plugin. One of them will be used.
Please let me know, how to resolve the warning or a better way of implementing the scenario.
The issue is a name class of the two ClassA types found in both plugin and library
I assume you have control over the source of either plugin / library.
.. rename Class A in one instance to make the names not clash -- I don't think there is another way to get rid of the warning/error

module.map for accessing (Swift and Objective-C) classes in main target from test target

I am in the process of adding Swift classes to an existing Objective-C project. As part of this, I have added a MyProjectTests.swift to the target MyProjectTests. It imports Swift classes from target MyProject with import MyProject and that works just fine.
I now want to use #import Swift; in MyProjectTests.mas well. However, the compiler issues the error Module 'MyProject' not found.
I have these questions:
Make both import and #import succeed in test target
Why can it be the case that the Swift compiler sees module MyProject but the Objective-C compiler does not? What build settings in MyProjectTest do I have to change to make #import MyProject succeed as well.
Export Objective-C classes from main target
Ultimately MyProjectTest.swift and MyProjectTest.m also need access to Objective-C classes from target MyProject. So far I have multi-targetted such files, but I want to switch to using modules also here.
My current understanding is that this is a matter of providing a module.map file which would list header files for the classes I wish to "export".
What are the exact steps I have to go through? Where should I place the header file and which build settings do I need to change in the two targets MyProject and MyProjectTests?
I currently have a (so far empty) module.map inside my project and build settings for target MyProject include Defines Module: Yes, Product Module Name: MyProject.
UPDATE I am by now wondering whether it might be impossible to expose (Objective-C) files from an iOS application (instead of framework) project as a module. But then it already seems to work for Swift files (somehow).
I've by now concluded that this is not possible with current Xcode (6.1.1) tooling. (What a waste of time!)
The old scheme of bi-targeting source files to both MyProject and MyProjetTest also presents several challenges for a mixed Objective-C/Swift project with a non-trivial amount of code:
Its Objective-C part defines a legacy NS_ENUM(Integer, Repeat) which name-clashes with Swift.Repeat<T>. Referring to it as MyProject.Repeat (not MyProjectTests.Repeat) causes problems when compiling for target MyProjectTests, which changing this target's Project Name (also) to MyProject (not: MyProjectTests) does not seem to solve.
Compilation of constructs where Swift class A employs Objective-C class B, which in turn employs Swift class C does not seem to be possible in a straightforward way. Since the compiler has not yet produced MyProject-Swift.h with the definition of C, it cannot compile B. But since it cannot compile B it cannot compile A and therefore cannot produce MyProject-Swift.h. Catch 22, or so it seems.
Bi-targeted Swift code imports Swift classes from auto-generated MyProject-Swift.h. For the target MyProjectTests this name does not apply, yet that's what it is in the source files. I did not want to go down the road of changing MyProjectTests' Project Name (see above). Importing the right auto-generated file via the targets *.pch may be possible, but then it may be not ...

Xcode 6 Beta 4 - Import swift class in the Test Target

I have downloaded Xcode6B4 and I encounter a problem that never happened on the beta 3. I defined several swift files with some extensions on basic swift types. When I want to call a method defined in theses files from the test target, the compiler does not find the definition of the method. Is that related to new keywords defining the access levels ?
By the release notes, all methods and properties are internal by default. The test target is a different module so anything you want to call from the test target must be declared as public.

isMemberOfClass with static library linked twice

I'm working on few plugins for Quartz Composer, that all link to the same custom static library copied for each of them in the bundles frameworks folder. The plugins could be used separately, so I have to distribute the library in each plugin.
Everything goes well, apart from the isMemberOfClass and isKindOfClass methods. I read here that importing twice the same classes could be the origin of the problem.
I have no error at compilation.
Let's say that I have 2 plugins (NSBundles) that contains the lib XCode project and compile it before linking to it.
They both copy the lib in their resources folder.
Then, they both instantiate a custom hOzPolygon2D class from that library.
The first plugin return true to the test of the hOzPolygon2D object with isMemberOfClass method.
The second return false.
isKindOfCLass method returns the same "error".
I can't imagine a solution in my case. I'm really not a compilation professional and would really appreciate some help.
You should distribute the static library separately (possibly as its own framework). From the question title I assume you're seeing duplicate symbol errors from the linker. If you statically link the same static library into multiple other libraries and then try to link an application to more than one of those libraries you're bound to see these duplicate symbol issues. I haven't actually tried this with frameworks, but I know of this issue from linking iOS apps against interdependent static libraries.
You shouldn't worry about the fact that the modules can be used separately. Just make sure your users can also get the base library. This is a normal situation. For example AppKit and UIKit depend on Foundation, but neither of them actually contains a copy of Foundation.