Multiple static libraries, swizzling and dispatch_once - iphone

I have a main application, let's call it App.
It links two static libraries, StatLib1 and StatLib2.
StatLib1 links the StatLib2 library.
As you see, the StatLib2 library is linked twice.
In a category of the StatLib2 library, I'm doing some swizzling:
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(#"test");
[self itk_swizzleInstanceMethodWithSelector:#selector(someMethod:)
withNewSelector:#selector(itk_someMethod:)];
});
}
test is logged twice, meaning the methods will be swizzled back to original.
I'm sure that this is the issue, since when I remove the link of StatLib2 on the App target, this does not happen.
First of all, why does this happen?
How can I fix this, without actually removing the link to StatLib2 on the App target?

First of all, a static library is just an archive of object files, so
you cannot really link one static library against another static library.
What probably happens is that all objects of StatLib2 are copied into
StatLib1. Later, when the application is linked, another copy of StatLib2
is added to the executable.
So you end with two "instances" of the load method, each with its own
static dispatch_once_t onceToken. Both methods are called when the class
is loaded, and each one executes its own dispatch_once() block.
This is also shown by the output of
NSLog(#"test: class=%p, token=%p", self, &onceToken)
test: class=0x7fff7c76cdc8, token=0x100021f60
test: class=0x7fff7c76cdc8, token=0x100021f98
The class is the same (because it is a category for the same class), but the
onceToken is different.
As a solution, you should only link the final executable against both
static libraries.

Related

ARC Semantic Issue: No visible #interface for Class declares the selector

Pretty basic stuff but i am unable to troubleshoot where the problem is. In my project, i have a class named "TheFeedStore" with following two methods:
- (BOOL)hasItemBeenRead:(RSSItem *)item
{
............
}
- (void)markItemAsRead:(RSSItem *)item
{
.........
}
I am using the following class method so other classes can access these methods using it:
+ (TheFeedStore *) sharedStore
{
static TheFeedStore *feedStore = nil;
if (!feedStore) {
feedStore = [[TheFeedStore alloc] init];
}
return feedStore;
}
In one of my another class, i can easily access the above methods by writing
if ([[TheFeedStore sharedStore] hasItemBeenRead:item])
or
[[TheFeedStore sharedStore] markItemAsRead:entry];
But in another class if i try to access these methods in a similar manner, i get the error "No visible #interface for 'TheFeedStore' declares the selector 'hasItemBeenRead:"
1) I have imported TheFeedStore.h file in the classes from i am
accessing these methods of TheFeedStore class.
2) I have checked like 10 times and there is no typo.
3) The methods i am accessing are also declared in the header file of
TheFeedStore.h
UPDATE: Just to check, i have declared another test method in TheFeedStore.h, same result, one class can access the newly created method while rest of the three classes cannot.
UPDATE: I have tried creating more methods in the TheFeedStore.h just for troubleshooting this issue. The new methods are also not accessible from the other classes. But if the return type of these new methods is (RSSChannel*) which is another model class in my project, than they become accessible. If their return type is other than some class like (void) and (BOOL) then they are not accessible. Here is my TheFeedStore.h https://gist.github.com/jessicamoore112/5558473
You have said that you are using #class instead of #import in your header files, the methods that you are trying to access are declared in the header files and there are no typos of any kind.
In such cases, usually no body points this issue but i am going to do it anyway because i have faced such issues many times. You have probably created many copies of your project to work on each functionality and also keeping a working project.
When you do this, sometimes Xcode is still using the older copies of few files. That means it is still using the older copy of the TheFeedStore.h when the methods you are trying to access were not declared by you.
How to solve this problem is very simple. Go to the file from which you are trying to access the methods and the files in which these methods are declared.
In the Utilities section on the right hand side, check the location and full path under "Identity and Type" area.
First check the names of the project, if it is different from the project name that you are working on, that means Xcode is still pulling the old copies of the files from the previous revision of your project. See the blue arrows where the project name is 13SampleMoreRequests in my case.
If this name is same as your project name, then my answer does not solve your problem. If its different, you should use the new copies of the file by browsing the new location using the sign that is pointed out by red arrow.
Once you browse and use the new files, your problem will be solved and you will be able to access the methods. If you still can't, copy these files, delete from the project and then add them again and you won't face this problem.
Hope this helps!
Cyclical imports, e.g. A.h imports B.h while also B.h imports A.h is the most common problem.
In C, cyclical imports won't work and one of the imports will be silently ignored. Make sure you are not having a cyclical import. If you do, solve it (e.g. using forward declarations).
Import problems can be also easily inspected if you generate the preprocessed output (you can find it in one of the Xcode menus).
That might sound silly, but I have similar cases once in a while and sometimes just simple quitting and starting xcode helps, it tends to stuck sometimes.
Also, sometimes cleaning the project helps.
'Cause I have very similar to yours singleton code and it works fine.
Guys I had encountered the exact same issues. After some searching on SO and the search engine I was able to solve it.
In my Case I have four files:
RadioStation.h
RadioStation.m
ViewController.h
ViewController.m
My mistake was to place all my methods in RadioStation.m and only put my variables on radioStation.h
So when I import radioSation.h on my ViewController.m and try to define methods for button-click on my app that's where the problems started.
I got the error/warnings "ARC Semantic Issue: No visible #interface for Class declares the selector" every time I built or ran the app simulator.
My Solution was to go back to RadioStation.h file and just declare all my methods there.
Since they were already defined on RadioStation.m I was good to go.
So make sure you have properly declared your methods on the file that is going to be imported on your viewControllers.
Hope that helps.
In my case I had some very strange path entries in
Framework Search Paths
Library Search Path
(Targets -> YOUR_APP_NAME -> Build Settings in "Search Paths" section)
I removed them and the error messages are gone.

iPhone - How to modify a static library (.a file)

I was given an static library (.a extension file) that I have to use in a project, however I need to modify some of the source code before it is useful to me. What is the best way to accomplish this?
The easy-but-most-of-the-time-not-applicable solutions are subclassing or extending.
You can also try to decompile the .a file if its licence authorizes it: cf. Decompiling Objective-C libraries, but it can be tricky and/or illegal.
You cannot modify a static library, your best bet is to try to get access to the sources or ask the author to modify it for you.
You may use a Objective C extension.
For example, there's a [MyClass myMethod] in the .a lib, and you want to change this one, the following code might be used:
#import "MyClass.h"
#interface MyClass( CategoryName )
-(void)myMethod;
#end
#implementation MyClass( CategoryName )
-(void)myMethod
{
//new implementation goes here
}
#end
You cannot modify a library, only extend. That's kind of the point - to distribute the functionality behind your code without people being able to read it.

Duplicate Symbol XCode duplicate library for same library?

Do you have any idea?
Why XCode compilation give this result?
ld: duplicate symbol _kJSONDeserializerErrorDomain in
/Users/Shared/_BUILDS_/Debug-iphoneos/libLACDLibrary.a(CJSONDeserializer.o)
and /Users/Shared/_BUILDS_/Debug-iphoneos/libLACDLibrary.a(CJSONDeserializer.o)
I have exactly the same problem. And it only complains for arm6 build (not arm7 build). I found a workaround: remove "-all_load" in Other linker flag under Build<-Get Info<-Target. I am not sure whether it is a correct workaround. I hope somebody can explain further and provide the correct workaround if this one is not.
This error occurs if you link the same library into your project multiple times.
Project dependencies are subtly different from linking the libraries together. It is okay to have several projects depend on the same shared library project X; however, make sure that only one of the projects actually links the library.
Hey, you probably have a duplicate reference in XCode to CJSONDeserializer, so it's compiled and linked twice.
I hit this issue with code like the following in a file called Common.h:
void dumpViews(UIView* view, NSString *text, NSString *indent) {
// ...
}
By adding static in front of the method definition it cleared the problem up for me:
static void dumpViews(UIView* view, NSString *text, NSString *indent) {
// ...
}

Interface Builder can't see classes in a static library

I have refactored some UIView sub-classes into a static library. However, when using Interface Builder to create view components for a project that uses the static library I find that it is unaware of the library classes. What do I need to do to make the class interfaces visible to Interface Builder?
Update: The correct answer refers to dragging the headers into the 'XIB browser'. The '.h' files can be dragged from a finder window to the window area identified in this image:
alt text http://img211.imageshack.us/img211/1221/xibbrowser.png
Try dragging the static library into your xib browser in Interface Builder. I haven't tried this with a static library, but the concept is the same. When you drag header files into IB, you can access those classes.
LexH, try linking with the -ObjC flag when building your static library. That worked for me... for about a year :-) I found this post as the problem has returned with a fresh OSX install and an upgrade in xcode. But it worked in XCode 3.1.2.
David
Add the same problem as LexH. It worked only when I called a dummy class method.
The problem was that I did not add my static library to the "link binary with libraries" under target.
Strangely everything else worked.
I followed this guide to link with my static lib Create static lib
I had the same problem. Dragging the library or headers to XIB Browser didn't work. Read Class Files didn't work. So I called:
[MyLibraryClass version]; // Substitute your class name for "MyLibraryClass".
This worked. version is a class method of NSObject, so all subclasses of NSObject inherit it.

Packaging a Bundle with a static library

I have a static library that includes some xibs. These will basically be the same across projects. I'd like to include the xibs as part of the library. I can include their veiwcontrollers, reference these controllers in the calling project but then there isn't a xib to load. When I right click the xib in the library project, it can't be part of the target.
I thought about creating a CFPluginBundle but that creates a new project. I'd loose all of my IBOutlet and IBAction references. What is the best way to reuse xibs that also have outlets and actions to specific controllers?
Here more discussion about it: Can you reference Xib files from static libraries on the iPhone?
I had the same problem when I wanted to export my project as a library for other developers to use.
I found the perfect solution to my view and it seems it will answer yours too.
There is an xcode plugin that allows you to build your project as a library which includes the resources as well.
https://github.com/kstenerud/iOS-Universal-Framework
I do not know the guys that built this plugin, but it works like a charm
I'm not sure what you mean by "include the xibs as part of the library", since static libraries can't have resources--but they also aren't shipped stand-alone, so they don't need to. If you just want code re-use for your own projects, you could keep the xibs where-ever you keep the static library, and just include the xibs in any project that uses the library.
If you go the CFPluginBundle route, you can make new bundle targets in an existing project; there's nothing magic about the templates, they just take care of making dummy files and turning on the right build settings. You can copy those into a new target in your existing project and it will work just fine. That said, I'm not sure what you mean about losing IBOutlet and IBAction references, since that information is part of the xib (and the class you are using in the xib), not the project.