How to create categories dynamically in objective c? - ios

I'm working on an objective-c library project ('MyLib').
Let's say this library is then included in 'TestApp'. Now, 'TestApp' also includes another library called 'Xlib'. This Xlib has a class C1 which has a method m1.
//C1.h is part of Xlib
#interface C1
- (void) m1;
#end
Now, every time m1 is called, MyLib should execute a piece of code.
My approach was, if I create a category in MyLib:
#interface C1 (mycat)
#end
#implementation C1 (mycat)
+ (void) load{
//code to swizzle method in class C1 from: #selector(m1) to: #selector(mycat_m1)
}
- (void) mycat_m1{
/*
insert code that I want to execute
*/
[self mycat_m1]; //calling the original m1 implementation
}
#end
Problem:
MyLib doesn't have the class C1. So I can't build MyLib as I'm trying to create a category on a class which doesn't exist. Hence, compilation errors.
So, then I tried to wrap the above code inside:
#if defined(__has_include)
#if __has_include("C1.h")
/* above category code */
#endif
#endif
MyLib compiles and builds fine now, but since C1.h is not present in MyLib, the mylib.framework wouldn't have this category.
Now, I have two options:
1. Create this category dynamically, so that once the library is included in the app, and then when the app runs, this category will be created depending on whether TestApp includes Xlib or not.
2. Remove the file which has this category code from compile sources, and then somehow expose that file in my framework to TestApp.
I'm not able to solve either of the options. Any ideas on the existing options? or any new options?
Edit: Added details since the question wasn't quite explanatory

This code doesn't need to be in a category.
Categories are often used when swizzling because most of the time, people are trying to "wrap" a function with their own behavior in a specific class. Swizzling is often done in the +load class method. The load class method on a Category is a nice place to put it organizationally, because you know the main class's +load method has just been called.
Swizzling is still quite possible in your case. Implement a class in your framework with a +load method. The swizzling code will go there like usual. You just need to lookup the Class you want to swizzle, instead of assuming the target reference is to self like it would be if this was in a Category. That is, if you are referencing a blog post or using a favorite technique to swizzle that references self, know that it likely won't be. Make sure you watch out for what class you are trying to swizzle to/from.
I've had to do something similar in the past. In my case, I had to look up the instance of the class that implemented the AppDelegate protocol from a Framework. In that case, the code that triggered the swizzling wasn't called from +load (since the AppDelegate class might not have been loaded, and the instance of the class for the AppDelgate definitely wasn't instantiated). In that case, I invoked the code from my class's -init method, and protected it so it couldn't be called twice. However, I was guaranteed to be able to instantiate my class from the app code, so the technique worked; I'm not 100% sure of your use case. It wouldn't hurt to post the code you've tried.
UPDATE: concrete example
Here is the method I keep handy for swizzling.
+ (void)swizzleSelector:(SEL)sel1 onClass:(Class)class1 withSelector:(SEL)sel2 fromClass:(Class)class2
{
Method method1 = class_getInstanceMethod(class1, sel1);
Method method2 = class_getInstanceMethod(class2, sel2);
// Make sure that both methods are on the target class (the one to swizzle likely already is).
class_addMethod(class1,
sel1,
method_getImplementation(method1),
method_getTypeEncoding(method1));
class_addMethod(class1, // The swizzling is 'on' the first class, so it's the target here, not class2.
sel2,
method_getImplementation(method2),
method_getTypeEncoding(method2));
// Once they are both added to the class, exchange the implementations of the methods.
method_exchangeImplementations(class_getInstanceMethod(class1,sel1),
class_getInstanceMethod(class1,sel2));
}
Like I said, you'll need to lookup the class of your target somehow, but assuming you are calling this from the class that has your replacement methods, and assuming m1: is the target selector you are trying to swizzle, you might invoke like this:
Class class = NSClassFromString(#"C1");
// Check that `class` is not `nil`
[self swizzleSelector:#selector(m1)
onClass:class
withSelector:#selector(my_m1)
fromClass:self];
I hope this helps to clarify what you can do with swizzling. 999 out of 1000, you probably don't need to swizzle. Your use case sounds like a possibility where you might have to.

Related

Objective C: Declaring a selector but implementing it in objects category

I have a framework in obj-c which is included by other modules. I want to allow the modules which are going to include it to provide their own implementation for certain methods.
I can't use subclassing because of some issues around serializing these objects. So, have to rely on using category.
I am thinking of declaring a method/selector for the object and then modules will define the category and implement that method. Something like below:
Framework will declare interface like below:
#interface framework:NSObject
- (void)methodToBeImplemented;
#end
#implementation framework()
- (void)invokeClientDefinedMethod
{
if([self respondsToSelector:#(methodToBeImplemented)]) {
[self methodToBeImplemented];
}
}
//Module-1 will link against this framework and define the category
#implementation framework(methodImplementor)
- (void)methodToBeImplemented
{
...
}
#end
Can I choose not to implement methodToBeImplemented at all in framework and implementation to be provided by the modules themselves.
I know that I can do it performSelector route. But I cringe to do so because I want to send pointers to my method which is not really possible with performSelector
If possible, I would highly recommend using a delegate pattern for your object so that callers can pass a delegate that conforms to a protocol rather than directly extending the class. That's the normal way to implement this kind of system. But if there's a particular reason a delegate is not possible, you can build what you're describing.
What you're looking for is an informal protocol, which is how almost all protocols were handled prior to the introduction of #optional.
What you want to do is define a category on your class in your public header:
#interface Framework (OverridePoints)
- (void)methodToBeImplemented
#end
This declares that such a method may exist, but it does not enforce its actually being implemented. The key is having a name in the parentheses. This can be anything (I used "OverridePoints" here), but it cannot be empty since that would be an extension instead of a category.
Once you have that, then the rest of your ideas work. You can test for respondsToSelector:, and the consumer can implement (or not implement) the category methods just as you describe.
The one danger is that there is nothing preventing multiple parts of the program implementing the same method in categories. That is undefined behavior, but the compiler will not catch it for you.

Do I need to declare a method prior to the first use of the method in same class?

I am new in Objective C, and working in C/C++ till now.
In C/C++, if function do not know prototype of function, it will not call that function, even if it is in same file. So we either use header file, or write prototype before using it. Like,
void proto(void);
void somefun()
{
proto(); //call the function
}
But in Objective C, I have function in same file, but I can call it without giving its prototype. Following is code which is compiling correctly.
//calling before actually declaring/defining, but works fine.
[self processResponse:responseObject];
-(void)processResponse:(id)responseObject
{
}
Can Objective C calls functions without knowing prototype if it is in same class? What should I prefer?
Please note that processResponse is internal function. I do not want it to expose it to any other class.
Can Objective C calls functions without knowing prototype if it is in same class?
Yes it will try to call it.
What should I prefer?
It is better to declare the function in private extention part of the implementation file(.m) since you dont want to expose that function to other class.
Advandtages:
1.Other Peer can understand the method only as internal
2.Other than that class, no one can access it.
in Implementation file(.m)
#interface MyClass ()
-(void)processResponse:(id)responseObject;
#end
#implementation MyClass
#end
You are comparing functions with methods. Functions still have same rules as in C. As for objective C methods there are no prototypes. You may declare the method in header or as a class extension but those make them public. As for protected methods you do not need anything, just create the method and call it from anywhere inside the class.
It used to be that you had to put these privet methods on top of the class to use them (method B could call method A only if method A was written above the method B) but that was a long time ago.
Just like in C in Objective-C you have to declare a function before using it. What you are doing in your example is not calling function before declaring it but sending a message (or invoking a method if we want to use a more OOP terminology) to an object. Which is a different thing.
Anyway for all the versions of the LLVM compiler included in Xcode starting from version 4.3 the order of methods declaration doesn't matter anymore since if the compiler encounter a not yet declared method it will look in the rest of the #implementation block to see if it has been declared later.

what does do method class in objective c

This might be a silly question. I'm learning objective C (iOS) by studying the code and I came across the expression
[InstanceName class];
What does it do?
I tried to search for class method but It just pops up difference between class method and instance method etc. I guess it might give some sort of class object but I have no idea what is the purpose of the statement.
the original code is Sample Facebook App (scrumptious) using FB SDK....
If you see something like this as a standalone expression....
[InstanceName class];
... then the code is most likely forcing the execution of the +initialize method on said class. The first time any method is invoked on a class, the +initialize method will be invoked prior by the runtime. So, have a look at InstanceName and see if it has a +initialize method.
Note that forcing +initialize to execute in this fashion is a sure sign of bad design. +initialize should never need to be forced like this and should not have execution order dependencies.
There is a legitimate additional reason why this line of code might exist. By referring to InstanceName with a hard reference, it'll force the linker to link in all symbols in the library. (If you don't have a hard reference to at least one symbol in a library -- a .a -- some linkers will simply drop the library from the link unit entirely.)
It gets the class of the object.
So for instance if InstanceName is an instance of class Foo
[InstanceName class]; will return Foo, in a variable of type Class
You can use class_getClassName to get an NSString from this class to log it.
class is a method inherited from NSObject. It lets you get the instance of the class object representing the class of the instance on which the method is called.
It can be used to examine the metadata of the current object. For example, you can use class method to determine if a given object is of a particular class:
if ([sender isKindOfClass:[UIButton class]]) {
...
}
It returns the class of the object. Suppose you have an array of UIView subclasses you created and you want to perform some action only to those who belong to a certain class. You could loop through the array and check for each object's class:
for (id view in myViews) {
if ([view isKindOfClass:[MyUIViewSubclass class]]) {
// Do something
}
}

NSObject's category is available for every NSObject subclass even without any import of this category's .h file anywhere

Background.
Please consider the following steps:
1) In Xcode create a new "Single View Application".
2) Create a category NSObject+Extension.h and .m files:
// .h
#interface NSObject (Extension)
- (void)someMethod;
#end
// .m
#implementation NSObject (Extension)
- (void)someMethod {
NSLog(#"someMethod was called");
}
#end
3) Ensure that NSObject+Extension.m file is included into a main target.
4) Add the following line to AppDelegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[NSString new] performSelector:#selector(someMethod)];
return YES;
}
5) Ensure that #import "NSObject+Extension.h line does not exists anywhere in the app!
6) Run Application.
The output is
2013-08-27 04:12:53.642 Experimental[32263:c07] someMethod was called
Questions
I wonder if there is no any #import of this category anywhere in the app, how is it even possible that NSString does still have NSObject+Extension available? This behavior makes me feeling very bad about every Objective-C category I declare because I want the categories I declare to be available only in the scopes they are declared within. For example, I want NSObject to be extended by Extension only in some class but not in the whole app because its globalspace becomes "polluted" otherwise.
Is there a way to avoid this behavior? I do want my categories to work only when I explicitly import them, not when I just have them linked to a target I use to run.
I wonder if there is no any #import of this category anywhere in the app, how is it even possible that NSString does still have NSObject+Extension available? This behavior makes me feeling very bad about every Objective-C category I declare because I want the categories I declare to be available only in the scopes they are declared within. For example, I want NSObject to be extended by Extension only in some class but not in the whole app because its globalspace becomes "polluted" otherwise.
There are no namespaces on Objective-C objects. If you declare that a class has a method (whether via a category or on the primary #interface) then every instance of that class will have that method.
The way that Objective-C deals with "private" methods is by choosing not to tell other people about the methods in question (which is accomplished by not #import-ing the file that declares those methods). This, coupled with -Wundeclared-selector (warn if you use a selector that the compiler doesn't know about) is about as good of a guard as you're going to get.
But regardless, if you compile the .m file into your final binary, the method will exist, even if no one else "knows" about it.
Are there way to avoid this behavior? I do want my categories to work only when I explicitly import them, not just when I have them linked to a target I use to run.
Yeah, use -Wundeclared-selector, and Xcode will warn you.
Including the header just makes it so the compiler knows about it. It compiles it regardless because xCode compiles every file included in a target. At runtime, the method will be there, so even if you didn't include it for compile time checking, the object will still respond to that category method.

How to create a class which is sub class of two classes

I have class called ViewController. How to make this class is a sub-class of "metaiosdkViewController" and "JWslideViewController". Help me with syntax.
i have written like this
#interface ViewController : MetaioSDKViewController,JWslideViewController
but this giving me error
objective-c doesn't support multiple inheritance,but if you want to add some extra behaviour you can achieve it through delegates..
yes objective-c doesnt support multiple inheritance but you can give one parent so
#interface ViewController : MetaioSDKViewController
and
#interface MetaioSDKViewController : JWslideViewController
this is just an idea I know you can implement well as per your need
What is it that you want to achieve with multiple inheritance?
Do you want to override methods from each of these super classes?
Note that objective c provides 2 mechanisms for extensibility:
1) Implementing a Protocol and make your object the delegate:
#interface ViewController : <MetaioSDKViewController,JWslideViewController>
This enforces ViewController to implement certain methods as defined in contract by 2 delegates, and at some point in processing, they get called. If you don't implement them, they may simply not be called but you may not get desired functionality.
Example: UITableViewDataSource protocol that defines many methods that UITableViewController subclass implements. cellForRowAtindexPath is very famous example of a delegate method that your own table view subclass must implement to draw your own custom cells.
Note that this is not the type of extensibility that subclasses provide in general sense. Your class does not extend any functionality here. Rather it becomes what it says - a delegate - someone who is assigned to do some task. Like you do:
yourTableView.delegate = self; //tell self to be the delegate of yourTableview
Library code does it's stuff and in some point in processing it calls [delegate someMethod]. If your own class implements it, it calls it, otherwise delegate will be nil, and it may just be NO-OP and you don't get desired functionality. Again, this is implementation-dependent. Maybe the protocol defines that the method is compulsory, in which case your class MUST implement this method in order to compile.
2) Implement a category:
This is sort of a shortcut way to extend library classes. They act like an extra stub which, when your code runs, attaches itself to the already existing memory layout of the library objects and provides extra functionality.
You can define a category on any of the in-built classes as well. In fact that is the primary objective it is used for. For example, here is an NSString category which provides HTML conversion. There are hundreds of categories implemented as open source and they provide enormous benefits where library code falls short. Discussing their suitability in entirety is however out of scope for this discussion.
One thing to note however is: You do not override anything using a category. Rather you are supplying something in extra. For example if you want some custom drawing across all your app views, you can define a category on UIView in your project and then all your views could simply include the category header file. You don't even have to inherit from this category, you simply inherit from the base type.
e.g. in the NSString category example above, you do not have to define your NSString to be of type NSString+HTML. Instead you just include the responsible NSString+HTML.h file wherever you want those extra methods like stringByConvertingHTMLToPlainText and so on. The changes remain limited to your project - to the files where you include this category.
Categories do not provide for extra data members - and that is something that only inheritance can provide. Yet, multiple inheritance among viewcontrollers is something you should definitely reconsider hundred times - you will see that what you are looking for is not multiple inheritance.

Resources