Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 years ago.
Improve this question
I know iOS Runtime is powerful and I have a question: where should we use runtime?
For example, I find many articles will discuss about class & method swizzling. And in which case should I use it?
I also google it and find it is widely used in jailbroken development. However, I'm a non-jailbroken developer, please don't cover jailbroken~
Thanks!
It's a very general question. The runtime is a library linked with your programs that implements part of Objective-C so it may show up anywhere. If you have to ask, don't use it. But FYI here are some common uses:
Swizzling
Swizzling is the exchange of the identifiers of two methods so they point to each other’s implementations. Both methods are still available.
It's useful to use swizzling instead categories to preserve the original implementation of the method, and to avoid having two categories overriding the same method (the result would be undefined).
See https://stackoverflow.com/a/8636521/412916 for a list of dangers.
Dynamic methods (sort of)
See https://stackoverflow.com/a/13646650/412916
Associative references
An associative reference is a way to add an instance variable to an object without changing its code. The associative reference is automatically removed when the object is deallocated.
Google it.
Introspection
Introspect the properties of the classes. For example to map between JSON and a plain class of your model. I guess Mantle and the Overcoat wrapper are examples of this.
You should read the Objective-C Runtime Programming Guide.
Using emoji as a method name
This is probably the most important use. The code is not mine and I don't remember the original author.
#include <objc/runtime.h>
#import <Foundation/Foundation.h>
#interface A: NSObject
#end
#implementation A
void pileOfPoo(id self, SEL _cmd) {
NSLog(#"💩");
}
+ (BOOL)resolveInstanceMethod: (SEL)name {
if ([NSStringFromSelector(name) isEqualToString: #"💩"]) {
class_addMethod([self class], name, (IMP)pileOfPoo, "v#:");
return YES;
} else return NO;
}
#end
int main(int argc, char *argv[]) {
#autoreleasepool {
A *a = [[A alloc] init];
SEL aSelector = NSSelectorFromString(#"💩");
[a performSelector: aSelector];
}
return 0;
}
Generally it shouldn't be used. When it is used it should be done with great care as the risk of breaking everything is high when you make a mistake. Usually it should only be done in well used code, preferably maintained as an open-source project so that many people check the validity.
It's not only used for jailbreak, but it does generally involve private classes / methods and allows you to workaround / expand limitations in the APIs. But it can also be used to expand by, for example, inserting your own class as an observer in some relationship so it can take some action and then forward the information to the 'true' observer (AFNetworking used to do this).
Generally you should use features like categories or standard subclasses to add functionality.
Method swizzling in runtime is a good measure to 'hook' methods whatever you want. Why do we need hooking? There are all kinds of application of hooking, such as user behavior statistic, automatic serialization and so on.
Here we take user behavior as a sample. With help of method swizzling, we can hook 'viewWillAppear' method in any UIViewController subclass. That means we can know when 'viewWillAppear' is called and thus we can inject user behavior codes(e.g. page visiting count, page visiting duration) before or after 'viewWillAppear' method. In summary, with help of method swizzling, we can easily make user behavior statistic realized. Other kinds of application are the same.
Related
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
When I was learning other languages such as Java, all the sample code tells you that you should always mark a field private. And the methods that do the internal stuff are also marked private or protected.
But when it comes to Swift, I see that the sample code from a lot of the tutorials (such as raywenderlich.com) seldom marks something as private. They just leave it internal (without adding any modifiers).
In contrast, all the android tutorials mark some of the fields as private and provide no getters or setters for them.
For example, I read this search bar tutorial a while ago:
https://www.raywenderlich.com/113772/uisearchcontroller-tutorial
When I was reading through it, I was thinking about: "Why did you not mark this private?"
let searchController = UISearchController(searchResultsController: nil)
I mean, it does not make sense for other classes to access the search controller of my VC. It's mine!
Question:
Why don't most, if not all tutorials provide sample code that contains private properties? Is it because iOS is more secure or something? Should I mark suitable stuff as private in production code?
I hope this is not too opinion based. In Java, you will never make a field public, right? That's just a fact - you should not make fields public. So please don't close as opinion based, it's not.
Why not everything private? There are several really common scenarios that I've seen that always favor having the variable either internal or public.
Delegate methods:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(
myCellID,
forIndexPath: indexPath);
return cell;
}
This method will be called not internally by you, but rather by the iOS system that manages and displays the tableView. The delegation pattern is widely used within iOS development.
Data exchange between two ViewControllers, where you simply want to set the other ViewController's field:
class MyVC1: UIViewController {
var flagShouldUpateColors = false {
didSet{
// some stuff
}
}
}
Then at some point you want to notifiy this ViewController that the flag should be set to true. You do that my simply acccessing it's field.
Also selectors. When I register an instance of a ViewController for some notification, I pass the name of a method that I have within the very same ViewController. It is to be called when the notification triggers. Basically what the code says is "please call this method for me when this occurs". If you say call this private method when this occurs, it wouldn't make sense would it ? How is the caller supposed to call it(aside from reflection and other unoptimized ways). Here is example:
override func viewDidLoad() {
NSNotificationCenter.defaultCenter().addObserver(
self,
selector: #selector(self.doStuffWhenEnterForeground),
name: UIApplicationWillEnterForegroundNotification,
object: app)
doStuffWhenEnterForeground();
}
func doStuffWhenEnterForeground() {
}
Main difference between Java and Swift is in properties.
Java has no concept of properties. It has fields and if you want to allow public access to those fields you can either access them directly or through getter/setter methods.
If you create public field that needs to be protected later on you will have to use methods and thus your public API will be changed - fields are accessed without parens and methods with them.
Swift is different in that regard. You can protect your field access with getter/setter at any point without changing API. So if you have field that is part of public API you can just leave it as is (without making it private) and without having getter/setter methods attached to it.
Encapsulation in Java and Swift are of the same importance. What differs is how it is achieved (implemented). Since there is no pressure for premature encapsulation in Swift and it is only matter of adding visibility specifier when appropriate there is some lack of discipline in adding those in tutorial code where main purpose is not enforcing encapsulation, but teaching some other concepts and how-to's.
Why don't most, if not all tutorials provide sample code that contains private properties? Is it because iOS is more secure or something? Should I mark suitable stuff as private in production code?
Probably because it's simpler, save few keystrokes and doesn't add unnecessary overhead to understanding the main theme of tutorial.
Should I mark suitable stuff as private in production code?
Yes, you should do it for the same reasons you would do it in Java. Notice 2 things, however:
There is no such thing as protected.
Access modifiers in Swift work differently compared to many other languages. private restricts access to variable or function to file where it was declared, regardless of who will access them. Thus, if you have 2 classes declared in the same file, they both can see private fields of each other. On the other hand, you can't see private fields even from extension of that class if this extension in other file. It looks strange at first and you just need to get used to it.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I'm a student in a internship, and i'm learning Objective-C in order to develop an IOS application. They already had an existing base of code, but some part of the code give me problems.
As the previous developer isn't in the company anymore, and because no one else know about Objective-C, no one can answer some of my questions about how the application is built, so I can't determine if it is that i don't understand, or if it's just bad practices.
Here are these questions :
1°) In some classes, i found code like this :
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated] }
This code is useless, right ?
2°) In like 9/10 methods in the project, they return (void). Is it a common pratice in Obj-C (because everything is a pointer) ?
3°) Sometimes there is the interface declaration in both header and messages files. I guess it's because you want to declare only a part in header for a future include, and to have a "private" part. But in a file, i find the following code :
In header :
#interface WebViewController : UIViewController
#properties ...
#end
In Msg file :
#import ...
#interface WebViewController ()
#end
#implementation WebViewController ...
What's the point declaring a void interface a second time in the msg file ?
4°) More, in another class, the interface is declared a second time too, but a method is defined (in the msg file). What's the point as the method is defined bellow, and is not declared in the header file ?
thank you in advance
Welcome to Objective-C :)
Not necessarily. The super class may have specific behaviour defined in it's own method implementation that would cause an issue if you didn't call it. Overriding methods means the super classes own method won't be called by default.
Added from comment: Of courser if you didn't override it then the superclass definition would get called just fine. There are 2 common reasons why you would find it overridden:
a. It's in the Xcode template so it has always been there and not been removed
b.it used to have other content but it was deleted and the method call left behind.
Yes. Although you don't explicitly return void in the method, you do need to specify some return type. If you're not returning anything then void is the right value. It's found commonly in obj-c classes as the method may respond to being called by mutating an internal ivar or property and not require a return. Alternatively the result might be to send a notification so a return value is not needed. Increasingly the use of block-based completion handlers replaces explicit value return as a way to respond to the contents of a method.
Yes, it's to give a private interface that you don't want exposed. In the case where there's nothing in the private interface it's probably there because it came with the template code from Xcode and no one removed it. You can ignore or remove.
For the one you mention with a method, while it's not required to declare private methods in an interface it makes sense from the point of view of writing readable code (a strongly endorsed concept in obj-c). Since the compiler will remove any unnecessary code it makes no difference to declare it and makes the task of reading the code and understanding the class that much easier when you or someone else returns to it later. It's a also a good place to put documentation in comments as it groups it all together.
Hope that helps. Check out the Objective-C programming guides from Apple to for more best practice tips.
1). Yes you can delete this method
2). It depends upon your requirement, whether you want a return type or not. e.g.
- (BOOL)isEmptyOrNull:(NSString*)str;
3). These are called extensions, you can read more about it here http://rypress.com/tutorials/objective-c/categories.html
Extensions are used to hide the methods from out side world(by saying hide I mean you can't find those methods with your eyes)
4). Methods define in implementation file are not visible to a programmer, it's just like private methods in java but in ObjC there is no such thing like private method. Read this thread for private methods Best way to define private methods for a class in Objective-C
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
I need some best pratices advice when checking conditions before running some methods.
Let's consider the following implementation :
#interface Foo : NSObject {
NSObject *_anObject;
}
#end
#implementation Foo
- (id)aMethod
{
if (!_anObject) return nil;
// do something
return obj;
}
- (id)aMethod2
{
if (!_anObject) return nil;
// do something
return obj;
}
Even if this implementation works well, I find pretty ugly to have these redundant checking codes if (!_anObject) return nil;.
So do you have some best pratices to avoid this ? (other than creating a macro to replace the line of code, which is pretty the same ugliness)
Thx in advance for your help.
Hmm, a few thoughts. I think it will depend a lot on what your // do something does.
If this is just a few methods, I think what you are doing is perfectly readable. And I agree a macro would only add confusing when reading the code.
Another thing to remember is in Objective-C you can call methods on a nil object safely, so maybe the check isn't necessary? Or you could try a null object-ish pattern. Usually used to prevent null pointer references which isn't a problem here, but maybe you could have a blank object that returns the correct thing if _anObject that makes sense in aMethod1 and aMethod2.
Another thought, if you are really checking for nil before all of your functions, perhaps you need to move up a level instead? It sounds like to me you have two classes. What about subclassing Foo with NilObjectFoo that just returns nil for all methods (or whatever)? Then when creating Foo, check if you have a _myObject and if you don't, create a NilObjectFoo instead. Then the rest of the code using that object doesn't care, and you are not cluttering up you Foo object with a bunch of nil checks.
Maybe a more concrete example would be helpful?
If I read you correctly (and I might not have), I would think that check of your belongs somewhere else. e. g.:
- (void)fooMethod{
if (_anObject){
// do whatever you need to do to the object, then:
NSObject *foo = [self aMethod];
}
}
- (id)aMethod{
// prepare the object you want
return obj;
}
This seems sturdier as you might need to have the result of aMethod used elsewhere even when _anObject is nil giving each fewer responsibilities. If you want a method to create several objects from different methods all depending on the state of _anObject you only need one outer if rather than the pattern you describe above:
- (void)fooMethod{
if (_anObject){
NSObject *foo = [self aMethod];
NSObject *bar = [self anotherMethod];
}
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 years ago.
Improve this question
I'm following the Stanford Developing iOS 7 course 2013 2014 on iTunes U (just for your info) and I'm having some general questions on the Objective C language. Thanks for your help!
Question 01
This is what I understood about #synthesize:
With the newest versions of Xcode there is no need to perform #synthesize for declaring a setter or a getter. It is done automatically for the programmer if the getter and setter is kept at default. However I have been taught I need to declare the synthesize when overrides BOTH the getter and the setter.
My question is: why only when BOTH are being overriden? It should make more sense to me you would need to declare the synthesize already when only one needs to be overridden?
Question 02
- (void)addCard:(Card *)card atTop:(BOOL)atTop;
- (void)addCard:(Card *)card;
Are 2 different public methods used in the course I'm following.
Question: Am I required to state these two as 2 individual methods. Couldn't I just use the first one, whilst specifying 2 different blocks of code to perform, by an IF ELSE clausule whether the BOOL is YES or NO? Wouldn't that be exactly the same outcome?
Question 03
Having a rather simple program with just a single view, I noticed I do not need to publicly specify any methods in my viewcontroller.h. I reckon this only would be needed if your program is more complex and contains several MVC where the controllers would need to "speak" to each other. Is this a right assumption to make, generally speaking, when making a proper MVC based program?
I thank you for your time and effort. Excuse me if my questions seem basic or do not make complete sense. I'm on the iOS learning path stage 1, with little OOP experience.
Question 1:
You are right about this. If you override the getter and setter then you need to #synthesize the property. I'll have to have a further look for why though.
Question 2:
Yes, you could just have the first method. However, the second method is there as a convenience and would normally contain code something like this...
- (void)addCard:(Card *)card
{
[self addCard:card atTop:YES];
}
Then the designated method would do something like...
- (void)addCard:(Card *)card atTop:(BOOL)atTop
{
if (atTop) {
// something to add card to top.
} else {
// something to add card at bottom.
}
}
i.e. it just routes the method call to the "designated" method but uses a default value for the BOOL.
Question 3:
The .h file is there as an interface file. It would be similar to a set of web services on a server. The class can do all sorts of stuff internally but it only needs to declare stuff in the .h interface file if something needs to access them externally.
For instance, you might have a class called Car. It might have a button called accelerator that would access an internal method and increase the speed. None of this needs to be exposed to external classes.
However, the same car might have a property called colour or a method called addFuel. These would need to be available externally so the user can see the colour and add fuel. These both need to go in the .h file.
I hope that makes sense.
Question 1: I have been taught I need to declare the synthesize when
overrides BOTH the getter and the setter. My question is: why only
when BOTH are being overriden? It should make more sense to me you
would need to declare the synthesize already when only one needs to be
overridden?
Once you use #synthesize you are using the setter/getter provided by the compiler. If you create your setter/getter without synthesize then you need to write both the methods, if you have readwrite property.
Question 2: Am I required to state these two as 2 individual methods.
Couldn't I just use the first one, whilst specifying 2 different
blocks of code to perform, by an IF ELSE clausule whether the BOOL is
YES or NO? Wouldn't that be exactly the same outcome?
Yes it is good to have two different methods. As these two vary on the parameters and the caller will know what is happening inside the method. If you wish to put if-else, for this you will require an ivar or a global value to check, but if you pass the BOOL no need for it.
Question 3: Having a rather simple program with just a single view, I noticed I do
not need to publicly specify any methods in my viewcontroller.h. I
reckon this only would be needed if your program is more complex and
contains several MVC where the controllers would need to "speak" to
each other. Is this a right assumption to make, generally speaking,
when making a proper MVC based program?
Even though you don't have any complex but always follow the architecture of MVC.
The controller in iOS programming usually refers to the view controllers. Think of a view controller as a bridge between the model and your views. This controller interprets what is happening on one side and uses that information to alter the other side as needed. For instance, if the user changes some field in a view, the controller makes sure the model changes in response. And if the model gets new data, the controller tells the view to reflect it.
Question 01
(edited) You need #synthesize to tell the compiler to create the ivar (eg. _myString) for you. You could also declare the ivar manually.
Question 02
You could just declare the first one yes. In fact the second one just a shorthand method, providing a default value for atTop. In most cases, you would implement the method exactly as you explained:
- (void)addCard:(Card *)card atTop:(BOOL)atTop {
if (atTop) {
// atTop == YES
}
else {
// atTop == NO
}
}
- (void)addCard:(Card *)card {
[self addCard:card atTop:YES]; // or atTop:NO, depending of the default value you want to use
}
Question 03
Again, yes. Your view controllers should expose as little properties and methods as possible, and make public only things that should be available for the rest of the application to use. So in the case of the single VC / single view program, having an empty VC interface is normal.
I have heard people state that method swizzling is a dangerous practice. Even the name swizzling suggests that it is a bit of a cheat.
Method Swizzling is modifying the mapping so that calling selector A will actually invoke implementation B. One use of this is to extend behavior of closed source classes.
Can we formalise the risks so that anyone who is deciding whether to use swizzling can make an informed decision whether it is worth it for what they are trying to do.
E.g.
Naming Collisions: If the class later extends its functionality to include the method name that you have added, it will cause a huge manner of problems. Reduce the risk by sensibly naming swizzled methods.
I think this is a really great question, and it's a shame that rather than tackling the real question, most answers have skirted the issue and simply said not to use swizzling.
Using method sizzling is like using sharp knives in the kitchen. Some people are scared of sharp knives because they think they'll cut themselves badly, but the truth is that sharp knives are safer.
Method swizzling can be used to write better, more efficient, more maintainable code. It can also be abused and lead to horrible bugs.
Background
As with all design patterns, if we are fully aware of the consequences of the pattern, we are able to make more informed decisions about whether or not to use it. Singletons are a good example of something that's pretty controversial, and for good reason — they're really hard to implement properly. Many people still choose to use singletons, though. The same can be said about swizzling. You should form your own opinion once you fully understand both the good and the bad.
Discussion
Here are some of the pitfalls of method swizzling:
Method swizzling is not atomic
Changes behavior of un-owned code
Possible naming conflicts
Swizzling changes the method's arguments
The order of swizzles matters
Difficult to understand (looks recursive)
Difficult to debug
These points are all valid, and in addressing them we can improve both our understanding of method swizzling as well as the methodology used to achieve the result. I'll take each one at a time.
Method swizzling is not atomic
I have yet to see an implementation of method swizzling that is safe to use concurrently1. This is actually not a problem in 95% of cases that you'd want to use method swizzling. Usually, you simply want to replace the implementation of a method, and you want that implementation to be used for the entire lifetime of your program. This means that you should do your method swizzling in +(void)load. The load class method is executed serially at the start of your application. You won't have any issues with concurrency if you do your swizzling here. If you were to swizzle in +(void)initialize, however, you could end up with a race condition in your swizzling implementation and the runtime could end up in a weird state.
Changes behavior of un-owned code
This is an issue with swizzling, but it's kind of the whole point. The goal is to be able to change that code. The reason that people point this out as being a big deal is because you're not just changing things for the one instance of NSButton that you want to change things for, but instead for all NSButton instances in your application. For this reason, you should be cautious when you swizzle, but you don't need to avoid it altogether.
Think of it this way... if you override a method in a class and you don't call the super class method, you may cause problems to arise. In most cases, the super class is expecting that method to be called (unless documented otherwise). If you apply this same thought to swizzling, you've covered most issues. Always call the original implementation. If you don't, you're probably changing too much to be safe.
Possible naming conflicts
Naming conflicts are an issue all throughout Cocoa. We frequently prefix class names and method names in categories. Unfortunately, naming conflicts are a plague in our language. In the case of swizzling, though, they don't have to be. We just need to change the way that we think about method swizzling slightly. Most swizzling is done like this:
#interface NSView : NSObject
- (void)setFrame:(NSRect)frame;
#end
#implementation NSView (MyViewAdditions)
- (void)my_setFrame:(NSRect)frame {
// do custom work
[self my_setFrame:frame];
}
+ (void)load {
[self swizzle:#selector(setFrame:) with:#selector(my_setFrame:)];
}
#end
This works just fine, but what would happen if my_setFrame: was defined somewhere else? This problem isn't unique to swizzling, but we can work around it anyway. The workaround has an added benefit of addressing other pitfalls as well. Here's what we do instead:
#implementation NSView (MyViewAdditions)
static void MySetFrame(id self, SEL _cmd, NSRect frame);
static void (*SetFrameIMP)(id self, SEL _cmd, NSRect frame);
static void MySetFrame(id self, SEL _cmd, NSRect frame) {
// do custom work
SetFrameIMP(self, _cmd, frame);
}
+ (void)load {
[self swizzle:#selector(setFrame:) with:(IMP)MySetFrame store:(IMP *)&SetFrameIMP];
}
#end
While this looks a little less like Objective-C (since it's using function pointers), it avoids any naming conflicts. In principle, it's doing the exact same thing as standard swizzling. This may be a bit of a change for people who have been using swizzling as it has been defined for a while, but in the end, I think that it's better. The swizzling method is defined thusly:
typedef IMP *IMPPointer;
BOOL class_swizzleMethodAndStore(Class class, SEL original, IMP replacement, IMPPointer store) {
IMP imp = NULL;
Method method = class_getInstanceMethod(class, original);
if (method) {
const char *type = method_getTypeEncoding(method);
imp = class_replaceMethod(class, original, replacement, type);
if (!imp) {
imp = method_getImplementation(method);
}
}
if (imp && store) { *store = imp; }
return (imp != NULL);
}
#implementation NSObject (FRRuntimeAdditions)
+ (BOOL)swizzle:(SEL)original with:(IMP)replacement store:(IMPPointer)store {
return class_swizzleMethodAndStore(self, original, replacement, store);
}
#end
Swizzling by renaming methods changes the method's arguments
This is the big one in my mind. This is the reason that standard method swizzling should not be done. You are changing the arguments passed to the original method's implementation. This is where it happens:
[self my_setFrame:frame];
What this line does is:
objc_msgSend(self, #selector(my_setFrame:), frame);
Which will use the runtime to look up the implementation of my_setFrame:. Once the implementation is found, it invokes the implementation with the same arguments that were given. The implementation it finds is the original implementation of setFrame:, so it goes ahead and calls that, but the _cmd argument isn't setFrame: like it should be. It's now my_setFrame:. The original implementation is being called with an argument it never expected it would receive. This is no good.
There's a simple solution — use the alternative swizzling technique defined above. The arguments will remain unchanged!
The order of swizzles matters
The order in which methods get swizzled matters. Assuming setFrame: is only defined on NSView, imagine this order of things:
[NSButton swizzle:#selector(setFrame:) with:#selector(my_buttonSetFrame:)];
[NSControl swizzle:#selector(setFrame:) with:#selector(my_controlSetFrame:)];
[NSView swizzle:#selector(setFrame:) with:#selector(my_viewSetFrame:)];
What happens when the method on NSButton is swizzled? Well most swizzling will ensure that it's not replacing the implementation of setFrame: for all views, so it will pull up the instance method. This will use the existing implementation to re-define setFrame: in the NSButton class so that exchanging implementations doesn't affect all views. The existing implementation is the one defined on NSView. The same thing will happen when swizzling on NSControl (again using the NSView implementation).
When you call setFrame: on a button, it will therefore call your swizzled method, and then jump straight to the setFrame: method originally defined on NSView. The NSControl and NSView swizzled implementations will not be called.
But what if the order were:
[NSView swizzle:#selector(setFrame:) with:#selector(my_viewSetFrame:)];
[NSControl swizzle:#selector(setFrame:) with:#selector(my_controlSetFrame:)];
[NSButton swizzle:#selector(setFrame:) with:#selector(my_buttonSetFrame:)];
Since the view swizzling takes place first, the control swizzling will be able to pull up the right method. Likewise, since the control swizzling was before the button swizzling, the button will pull up the control's swizzled implementation of setFrame:. This is a bit confusing, but this is the correct order. How can we ensure this order of things?
Again, just use load to swizzle things. If you swizzle in load and you only make changes to the class being loaded, you'll be safe. The load method guarantees that the super class load method will be called before any subclasses. We'll get the exact right order!
Difficult to understand (looks recursive)
Looking at a traditionally defined swizzled method, I think it's really hard to tell what's going on. But looking at the alternative way we've done swizzling above, it's pretty easy to understand. This one's already been solved!
Difficult to debug
One of the confusions during debugging is seeing a strange backtrace where the swizzled names are mixed up and everything gets jumbled in your head. Again, the alternative implementation addresses this. You'll see clearly named functions in backtraces. Still, swizzling can be difficult to debug because it's hard to remember what impact the swizzling is having. Document your code well (even if you think you're the only one who will ever see it). Follow good practices, and you'll be alright. It's not harder to debug than multi-threaded code.
Conclusion
Method swizzling is safe if used properly. A simple safety measure you can take is to only swizzle in load. Like many things in programming, it can be dangerous, but understanding the consequences will allow you use it properly.
1 Using the above defined swizzling method, you could make things thread safe if you were to use trampolines. You would need two trampolines. At the start of the method, you would have to assign the function pointer, store, to a function that spun until the address to which store pointed to changed. This would avoid any race condition in which the swizzled method was called before you were able to set the store function pointer. You would then need to use a trampoline in the case where the implementation isn't already defined in the class and have the trampoline lookup and call the super class method properly. Defining the method so it dynamically looks up the super implementation will ensure that the order of swizzling calls does not matter.
First I will define exactly what I mean by method swizzling:
Re-routing all calls that were originally sent to a method (called A) to a new method (called B).
We own Method B
We dont own method A
Method B does some work then calls method A.
Method swizzling is more general than this, but this is the case I am interested in.
Dangers:
Changes in the original class. We dont own the class that we are swizzling. If the class changes our swizzle may stop working.
Hard to maintain. Not only have you got to write and maintain the swizzled method. you have to write and maintain the code that preforms the swizzle
Hard to debug. It is hard to follow the flow of a swizzle, some people may not even realise the swizzle has been preformed. If there are bugs introduced from the swizzle (perhaps dues to changes in the original class) they will be hard to resolve.
In summary, you should keep swizzling to a minimum and consider how changes in the original class might effect your swizzle. Also you should clearly comment and document what you are doing (or just avoid it entirely).
It's not the swizzling itself that's really dangerous. The problem is, as you say, that it's often used to modify the behavior of framework classes. It's assuming that you know something about how those private classes work that's "dangerous." Even if your modifications work today, there's always a chance that Apple will change the class in the future and cause your modification to break. Also, if many different apps do it, it makes it that much harder for Apple to change the framework without breaking a lot of existing software.
Used carefully and wisely, it can lead to elegant code, but usually, it just leads to confusing code.
I say that it should be banned, unless you happen to know that it presents a very elegant opportunity for a particular design task, but you need to clearly know why it applies well to the situation, and why alternatives do not work elegantly for the situation.
Eg, one good application of method swizzling is isa swizzling, which is how ObjC implements Key Value Observing.
A bad example might be relying on method swizzling as a means of extending your classes, which leads to extremely high coupling.
Although I have used this technique, I would like to point out that:
It obfuscates your code because it can cause un-documented, though desired, side effects. When one reads the code he/she may be unaware of the side effect behavior that is required unless he/she remembers to search the code base to see if it has been swizzled. I'm not sure how to alleviate this problem because it is not always possible to document every place where the code is dependent upon the side effect swizzled behavior.
It can make your code less reusable because someone who finds a segment of code which depends upon the swizzled behavior that they would like to use elsewhere cannot simply cut and paste it into some other code base without also finding and copying the swizzled method.
I feel that the biggest danger is in creating many unwanted side effects, completely by accident. These side effects may present themselves as 'bugs' which in turn lead you down the wrong path to find the solution. In my experience, the danger is illegible, confusing, and frustrating code. Kind of like when someone overuses function pointers in C++.
You may end up with odd looking code like
- (void)addSubview:(UIView *)view atIndex:(NSInteger)index {
//this looks like an infinite loop but we're swizzling so default will get called
[self addSubview:view atIndex:index];
from actual production code related to some UI magic.
Method swizzling can be very helpful is in unit testing.
It allows you to write a mock object and have that mock object used instead of the real object. Your code to remain clean and your unit test has predictable behavior. Let's say you want to test some code that uses CLLocationManager. Your unit test could swizzle startUpdatingLocation so that it would feed a predetermined set of locations to your delegate and your code would not have to change.