Stored Block Closure as IBAction - iphone

I am trying to reduce ceremony and out of academic curiosity I want to know how to do the following without the IBAction method defined in the .m file to use a closure whenever an Interface Builder wired action occurs such as a button press. You could say that I want to imply the cancelButtonPress method below instead of having to define it. A UIViewController subclass or some magic stored in a category would be quite acceptable.
#interface MyViewController : UIViewController
{
void(^doOnCancel)(void);
}
#property (nonatomic, copy) void(^doOnCancel)(void);
- (IBAction)cancelButtonPress:(id)sender;//I want this gone!
#end
I tried changing void to IBAction in the property and variable with no luck.
Edit: Alternative patterns that also reduce repetition in using closures for actions would also be useful.
The bounty is for a good pattern that will allow for closures to be arbitrarily used to service actions defined in IB in a way that could be used to reduce ceremony. The "can't do it" comments so far might or might not be correct.

Ahruman's approach is good, but it's probably relying too much on the runtime. Other than performance issues, Swizzling and using initialize is more susceptible to bugs if someone else wants to play with the runtime at the same time. I suggest using C macros.
Define these macros at the top of your class (or anywhere, really):
typedef void(^BlockAction)(id sender);
#define BlockActionProperty(ACTION) #property (copy) BlockAction ACTION;\
- (IBAction) ACTION:(id)sender;
#define BlockActionSynthesize(ACTION) #synthesize ACTION;\
- (IBAction) ACTION:(id)sender {\
if (ACTION) ACTION(sender);\
}
Now to create a new action, all you need to do is replace the #property ... in the header with the following (for example):
BlockActionProperty(testAction);
and "synthesize" it in implementation with:
BlockActionSynthesize(testAction);
At anytime if you want to override this and use the normal action method, all you need to do is synthesize and implement the action as usual.
This is faster (and in my view cleaner) than doing it at runtime, and since the IBAction is defined Interface Builder can "see" its definition.

Here you go, a hack to allow any block-typed property to be used as an action: http://gist.github.com/589740
It is, as you say, of academic curiosity. I really don’t recommend using it for reals.
Also, it doesn’t strictly live up to your requirement, since the action is declared in an unimplemented category. This is purely so that Interface Builder can find it automatically by scanning headers. You can delete that and add the action manually in IB’s inspector, but that seems like a loss to me since keeping it in sync properly is harder that way.

Without resorting to something like "Put the code that would normally be in cancelButtonPress: in forwardInvocation:," you can't. Interface Builder actions send messages. Calling a block cannot be the direct result of an action message.
It is possible to extend a control so that it calls a block instead of sending a normal action method to your controller, but that would require much more code, and it wouldn't magically make Interface Builder support it.

Related

When to use selectors in Objective C [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Using -performSelector: vs. just calling the method
I can accomplish the same task in my application by doing:
[self performSelector:#selector(displayOneLife)];
and:
[self displayOneLife];
Is it better to use one or the other depending on the situation? If so, can someone elaborate for me? I would just like to use Objective-C best practices.
Thank you,
Joey
The -performSelector approach is usually used when you would like to invoke some selector not known at compilation time. For instance, UIButton uses it to invoke the action you wire it up to when a user hits it (the button knows the name of the method it is hooked up in IB and the class it it hooked up to).
For all other cases you should go with the latter as you don't want to convert your code into an unreadable puzzle.
P.S. -performSelector + dynamic selector name construction can be used to work around Apple's static analyzer which seeks the binary for prohibited invocations :)
You can store a selector in a variable, so performSelector: is useful for when you don't know at compile-time what message you want to send. For example, the target-action system is based on selectors. Here's a rudimentary implementation of a control:
#interface FakeControl : NSObject
#property(nonatomic, strong) id target;
#property(nonatomic, assign) SEL action;
- (void)click;
#end
#implementation FakeControl
- (void)click {
[target performSelector:action];
}
#end
By using a selector, we can have the control send any message we want at runtime when it's clicked.
#selector has a very specific use, and you should not use it to call known methods.
You use #selector to inform other classes of one of your methods that should be called.
For example you can pass the class countNumber a selector to your method #selector(result:) so that the other class will call your method when it has completed its task.
example code:
- (void)calculateANumber
{
[NumbersClass countNumber:myNumber withResult:#selector(result:)];
}
//This method will get called by NumbersClass, even tho it didnt know its existence before
- (void)result:(int)countResult
{
myResult = countResult;
}
Just an example, obviously, it does nothing
If you have to do some thing inline especially on the same thread
[self displayOneLife]
is good enough
But there are many instances, where you want to do the execution on another thread, or after a delay etc. If you just type, [self perform ...], you will see so many suggestions for methods available for performSelector, each of the method signatures will help you understand what it does.
Select one of the methods and just command click on the method name. It will show you details about what the method does etc.
It is a very good question but has many answers. Runloops, threads, delays, asynchronous operations are all reasons.

Internal properties versus ivars

When I need a private object I currently use properties, like so:
// Class extension in .m file
#interface MyClass()
#property (strong, nonatomic) NSArray* myInternalArray;
#end
self.myInternalArray = something;
Alternatively you can do this:
#implementation MyClass {
NSArray* _myInternalArray;
}
_myInternalArray = something;
Without a custom setter or getter the two are equivalent. What is the best practice for internal variables? Are there any advantages of one method over the other?
While some may argue that the choice is a matter of preference, and they do have a point, there is a very good reason that most modern languages support properties and make them easier and easier to code.
The introduction of ARC does not significantly reduce the value of properties. It all comes down to this - in a property you have encapsulated the use of a variable. That encapsulation is invaluable when needed, and not much overhead when it is not.
For example (off of the top of my head) Suppose you discovered that you needed to validate the value before saving it. If you were using an iVar, you would have to ensure that anywhere that iVar was used, you had a call the validation code before you allowed it's value to be changed. With a property, you would only need to override setIVarName: and put the validation there. One could argue that one is just as easy as the other - and that may be true in many cases, but there is one handicap with the iVar here - you cannot ensure that future changes (by you or other coders) will insert the validation before the iVar is changed. Using a property here does have that assurance.
Personally, I use properties over iVars where ever possible.
I'd say that the advantage of properties is that you would use setters, and that setters can evolve independently of the code that call them. For instance, you could decide that setting a property would now trigger setNeedsLayout. By using properties from the start, you would have no need to refactor existing code.
This pattern fits very well in Cocoa/iOS APIs, where you don't have to ask system objects to do anything after having changed their properties: setters ensure internal and UI consistency right away.
The fact that properties are private should not make us implement them as second-class properties, what do you think?

Changing cell appearance when editing UITableView _without_ using custom cells?

If I am using a custom UITableViewCell I can use the following methods to change the cell's appearance when transitioning state:
- (void)willTransitionToState:(UITableViewCellStateMask)state
- (void)didTransitionToState:(UITableViewCellStateMask)state
Is there a way to achieve this if I'm not using a custom tableview cell?
Edit: Please see Daniel Hanly's comment. Categories may be selectively applied using #import. My apologies to anyone that may have been misled by this answer. Relevant sections will be redacted for future reference.
Okay, attempt number two. As far as I am aware, there is no other documented way to implement the functionality you require without subclassing UITableViewCell. It's worth noting that Apple's docs on UITableViewCell specifically mention that the state transition methods are meant to be implemented by subclasses. That having been said, If you absolutely need to implement them without a subclass, there are a couple of less conventional solutions. Each comes with its own issues, and it may end up being unfeasible for you to implement them, but it's an interesting question nonetheless.
Disclaimer
If you only want a sane and relatively simple explanation, then consider the answer to your question to be "no, there is no way to do what you want." I only present the options below with the assertion that they will work. In no way do I endorse actually using them. Consider this my penance for providing my first answer with such an obvious flaw.
Option One - Categories
It is possible to get the functionality you're looking for by overriding the methods you listed in a custom UITableViewCell category.
The problem is that this approach would be a pretty bad idea 99% of the time. Once you define the category on UITableViewCell, those methods would be defined for all UITableViewCell objects throughout the app. Unless you want the exact same state transition functionality for every single table cell in the app, this approach isn't very helpful.
Option Two - Runtime magic
You can use the low-level Objective-C runtime functions to change the implementation of any method on the fly. Unlike the categories option, this approach is flexible enough to redefine the intended behavior whenever you need to, instead of being a one-shot deal.
For example, if you're trying to manage state transitions from a UITableViewController, you could do this:
CustomTableViewController.m
#import <objc/runtime.h>
- (void) customStateWillChange:(UITableViewCellStateMask)state
{
//custom UITableViewCell code
}
- (void) viewDidAppear:(BOOL)animated
{
//Store the original implementation
Method originalStateWillChangeMethod = class_getInstanceMethod([UITableViewCell class], #selector(willTransitionToState:));
originalStateWillChangeImplementation = method_getImplementation(originalStateWillChangeMethod); //variable declared in header file as type IMP
//Get the new implementation
Method newStateWillChangeMethod = class_getInstanceMethod([self class], #selector(customStateWillChange:));
IMP newStateWillChangeImplementation = method_getImplementation(newStateWillChangeMethod);
//Replace implementation
method_setImplementation(originalStateWillChangeMethod, newStateWillChangeImplementation);
//the rest of your viewDidAppear code
[super viewDidAppear:animated];
}
- (void) viewDidDisappear:(BOOL)animated
{
//restore the original implementation
Method originalStateWillChangeMethod = class_getInstanceMethod([UITableViewCell class], #selector(willTransitionToState:));
method_setImplementation(originalStateWillChangeMethod, originalStateWillChangeImplementation);
//rest of viewDidDisappear code
[super viewDidDisappear:animated];
}
This code may not suit your exact purposes, but I think it provides a useful example.
It's incredibly ugly though because the customStateWillChange: method defined here is only intended to be run as a part of the UITableViewCell class, but in this example it will be compiled as though it were part of the CustomTableController class. Among other annoyances, you would have to eschew the property dot notation, ignore compiler warnings and give up most if not all compile-time checks for that method's body.
Option 3 - Category with runtime magic
Exactly what it sounds like. Define any custom state change methods you like within a category (or several categories) on UITableViewCell. Be sure that each one has a separate name - adding two categories that each have a method of the same name will result in undefined behavior. Also, each one needs to have the same return type and argument types as the method it is intended to replace.
Then the references to [self class] in the above code would be replaced with [UITableViewCell class], and the customStateWillChange: method would be moved to the custom category. While still ugly, you can at least rely on the compiler to interpret the method bodies properly.
Of course, messing with the runtime adds a whole lot of complexity to keep track of. It could work fine, but it's not good design, it would take serious effort to ensure it worked safely and correctly, and it would be likely to bring anguish and despair to anyone maintaining it.
References
The Objective-C Programming Language - Categories and Extensions
Objective-C Runtime Reference
Absolutely. The UITableViewDelegate protocol specifies a number of methods to manage state transitions for the table view's cells. Take a look at the UITableViewDelegate Class Reference, specifically the methods listed under the heading "Editing Table Rows".
Edit
Sorry, you're right. The UITableViewDelegate methods don't respond to direct changes to the cell's properties. I've found a way that does work, but I'm going to put it in a different answer to avoid confusion.

Can I store a custom object inside a button in Objective-C?

In winforms/C# most all UI Controls have a .Tag tag, so like myButton.Tag = myObject; where the Tag property is an 'object' type so you can basically store any type of object. How might I accomplish this in Objective-C/Cocoa? do all UI elements have something like .Tag where I can store an NSObject or something? If so, can you please provide an example. Thanks so much!
Note: I did see the integer .Tag there, but I wanted an object tag. But I guess that doesn't exist. hoo well.
As Georg said, you can associate whatever object to another object using the Objective-C runtime, so you can associate an Object to a control if you really want.
But that is not really how a standard Cocoa program works. Instead, in Cocoa, the Model-View-Controller pattern and the Delegation are the standard idiom, and associating an object directly to a widget or a view is discouraged. Even for a very small program, you would at least create a Model-Controller (called usually the application delegate in the Cocoa jargon) which manages the data, and keep the view composed of the standard controls as is. Then the view and the model-controller interact via target/action and delegation.
Apple has a very nice discussion of design patterns prevalent in Cocoa, see here.
In general, when you move from one API(Winforms/C#) to another API(Cocoa/Objective-C), there are some similarities but also some differences. It is usually worth learning how things are done in that API, rather than trying to shoehorn what you're used to into a new situation. (Just to be clear, I'm not saying which API is inherently better; this discussion goes both ways!)
So, when you are in a situation:
To do X in API A, I know the idiom P works. I now want to do X in API B. How can I directly implement idiom P in API B?
I recommend you to ask
To do X in API B, what should I do? What's the idiom in API B?
instead.
NSControl does have a tag and related setTag: method. It's not used internally so you can store whatever you like in it - it only stores NSInteger values though.
All Cocoa controls inherit from NSControl.
There is the possibility to add a tag, it's an integer if I remember correctly.
This said, I'm pretty sure one never needs this functionality in Cocoa, because it just doesn't work this way.
If you really want to add information you might be interested in the runtime's ability to associate an object with another object.
CALayers have the ability to store arbitrary keys as part of their key-value coding machinery. Example:
CALayer *myLayer = [button layer];
// Storing a value
[layer setValue:#"World!" forKey:#"hello"];
// Retrieving a value
NSLog(#"Hello %#", [layer valueForKey:#"hello"]);
That being said, storing objects against user-interface elements violates the principle of the Model-View-Controller pattern; I would advise against it--a UIView or UIControl subclass would likely be better suited.
Yep. You can add your own property to all UIControls if you like.
Just add the following to your code.
#import <objc/runtime.h>
/* -------- The Following Code adds an objectData property for every UIControl ----------- */
#interface UIControl (UIControlAdditions)
#property (nonatomic, retain) id objectData;
#end
static char const * const ObjectDataKey = "MyObjectDataKey";
#implementation UIControl (UIControlAdditions)
#dynamic objectData;
-(id)objectData {
return objc_getAssociatedObject(self,ObjectDataKey);
}
- (void)setObjectData:(id)newObjectData {
objc_setAssociatedObject(self, ObjectDataKey, newObjectData, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
#end
/* -------- The Above Code adds an objectData property for every UIControl ----------- */
Credits to Ole Begemann: http://oleb.net/blog/2011/05/faking-ivars-in-objc-categories-with-associative-references/

Call back style

I am writing an iPhone application which in numerous places needs to perform non HTTP or FTP networking of a very simple request response type.
I've wrapped all this up into a SimpleQuery class that integrates with the run loop.
SimpleQuery *lookup = [[SimpleQuery alloc] init];
[lookup setDelegate:self];
[lookup doQueryToHost:queryServer port:queryPort query:queryString ];
As you can see the calling object sets itself as a delegate. When the results are complete it then calls a method on the delegate with the results.
[delegate simpleQueryResult:resultString simpleQuery:self];
I am now in a position where I have a user of SimpleQuery that has two types of query so I need to extend SimpleQuery to support this.
I can think of two sensible ways of doing this.
Firstly passing a selector into doQueryString, or a seperate doQueryStringWithSelector.
[lookup doQueryToHost:queryServer port:queryPort query:queryString selector:#SEL ];
Secondly passing a tag into doQueryString so that when the delegate is called it can query the tag, as the simpleQuery is passed, to find out what the results are for.
[lookup doQueryToHost:queryServer port:queryPort query:queryString withTag:tag ];
I'm just wondering which is best from a coding style perspective, the first seems simpler but tagging seems more in keeping with the iPhone SDK and Interface Builder
An option which is used commonly in Apple's code (for example, in UIControl) is to provide both a target object and a selector. This works only if there is a single callback, and is more appropriate than a delegate in that case. (If there are multiple callbacks, then you'll probably have to go with a delegate and the tag approach.)
If you go this route, then you do away with the delegate altogether and instead have a method with a signature like this:
doQueryToHost:(id)queryServer port:(int)queryPort query:(NSString*)queryString target:(id)target action:(SEL)action
Note that "action" is typically preferred over "selector" in methods arguments in this case. The query would simply call the selector on the target when done. This would allow your clients to have multiple selectors, and also multiple target objects; this can help clean up code because you don't need to shove everything into a single delegate object.
If you want to go with your tag route, you should call it "context", which is what Apple uses (for example, in addObserver:forKeyPath:options:context).
There's a third option that's a common pattern in the kits, which is to use #protocols.
For example:
#protocol QueryCompleteHandlerProtocol
- (void)queryType1Complete:(int)intStuff;
- (void)queryType2Complete:(float)floatStuff;
#end
What this does is declare a set of method calls that an object adopting the protocol has to conform to (the compiler will actually enforce this).
So your SimpleQuery object will hold on to something like the delegate pointer, which you might declare like this among the ivars:
NSObject<QueryCompleteHandlerProtocol> *callback;
What this tells the compiler is that callback is an object that descends from NSObject and adopts the QueryCompleteHandlerProtocol protocol. Sometimes you see this written as:
id<QueryCompleteHandlerProtocol> callback;
When you want to call the callback there's nothing special about them, SimpleQuery's methods will just call:
[callback queryType1Complete:1];
[callback queryType2Complete:2.0];
Finally you client for the procotol class will declare itself as adopting the protocol:
#interface MyClass : NSObject<QueryCompleteHandlerProtocol>
...
#end
And will set itself as the callback with some code like:
[lookup setCallback:self];
This is where the compiler checks that MyClass conforms to QueryCompleteHandlerProtocol, meaning it has implemented queryType1Complete: and queryType2Complete:.
I'm not sure I understand the problem here. Can't SimpleQuery's user just set another delegate object for the second query, or branch on the simpleQuery: parameter? That's a basic part of the delegate pattern, just like having two UIActionSheets for one view controller.