Why shouldn't I subclass a UIButton? - objective-c

I've asked a few questions on stack overflow about subclassing a UIButton, and a couple of people have informed me that I shouldn't subclass a UIButton.
What are the negatives of subclassing a UIButton? And I know it's vague, but what are other alternatives to subclassing a UIButton?

The Cocoa frameworks take the approach that the Object Composition pattern is more appropriate than traditional class hierarchy.
In general, this means that there is likely to be a property on UIButton where you can set another object to handle various aspects of the button. This is the preferred way to "customize" how your button works.
One of the main reasons for this pattern is that many library components create buttons and don't know that you want them to create instances of your subclass.
edit, your own factory method
I noticed your comment above about saving time when you have the same button config across many buttons in your app. This is a great time to use the Factory Method design pattern, and in Objective-C you can implement it with a Category so it's available directly on UIButton.
#interface UIButton ( MyCompanyFactory )
+(UIButton *) buttonWithMyCompanyStyles;
#end
#implementation UIButton
+(UIButton *) buttonWithMyCompanyStyles {
UIButton *theButton = [UIButton buttonWithType:UIButtonTypeCustom];
// [theButton set...
return theButton;
}
#end

It's because UIButton is kind of special in that there are a few complexities/subtleties/restrictions (i.e. additional overrides for you to define, notably +buttonWithType:) required in order for it to work as expected. It's more than the usual -initWithFrame: (and -initWithCoder:, if used in XIBs). IDK why the framework authors allowed those details to leak out into our domain, but it's something that must be dealt with by us now. The restriction is that your implementation must not depend on (i.e. extend) preset system button styles; You must assume UIButtonTypeCustom as your starting point for a UIButton subclass.
On implementing a subclass of UIButton

If you are just looking for something more lightweight with your own 'subviews' you should instead be subclassing UIControl. UIButton subclasses UIControl and can handle events, like:
[mySubclassedButtonFromUIControl addTarget:self action:#selector(_doSomething:) forControlEvents:UIControlEventTouchUpInside];
UIControl subclasses UIView so you can cleanly layoutSubviews on any views contained by your UIControl subclass and avoid unnecessary views that come with UIButton. In essence you are just creating your own 'UIButton' but you avoid having to work around behavior and functionality you don't really want or need.

Related

IOS - The correct way for using #import classes

I am writing a test project to learn to write everything in code. I want to do this way so that I can better understand what the Elements in Storyboard do for me behind the scene's
In my project I have several UIViewControllers which share the same UI elements. For Example I have a UITool bar at the top of the screen with several buttons in it.
Now I want to put that UIToolbar in a separate class so that I do not have to write it all out or copy n paste it in every controller.
Now I know I can achieve this by doing this:
#import "General_Add_ons.h" //the UIToolbar is properly set up in this file
#interface FirstViewController : General_Add_ons
and then I just use [self topToolBar]; //topToolBar is the name of the toolbar
Now I just want to clarify is this the best and or only way to this?
Somehow I feel I should be able to do this:
General_Add_ons *gao = [[General_Add_ons alloc] init];
[gao topToolbar];
Am I thinking about this the wrong way? The first way seems to be limiting in case I have multiple external classes.
Thanks in advance.
Your approach seem correct. If you have several UIViewController instances that need the same UI elements or other controller code, you can put those elements in a UIViewController subclass. In your case, I believe the class General_Add_ons is the UIViewController from which your subclasses will inherit.
This class (your General_add_ons) should have a property for the reusable toolbar, e.g.
#property (nonatomic, strong) UIToolbar *toolbar;
As an aside, class names in Cocoa, by convention are: prefix+capitalized words without underscores. Apple has a great reference on naming conventions.
EDIT
For clarification, you can subclass your custom subclass as many times as you need. For example in my code, I have a class CCFViewController that encapsulates common properties and behaviors that I want all of my view controllers to have. In the project, then, all of the view controllers inherit from that parent controller. Similarly, your toolbar will live in the superclass and the other controllers inherit from it.
I am not 100% sure but i think you should try it this way:
General_Add_ons *gao = [[General_Add_ons alloc] init];
[gao.topToolbar anypossiblemethodcall];

Interaction between Subview and UIViewController with Delegates

I've read a lot of articles to get some information about the whole delegate concept in objective c. At least I think I got the general idea of that. But I didn't found an answer for my question - or I just found it but didn't got it...
In my case I got a custom subview I'm adding programmatically on my UIViewController. I want to have an interaction from the custom UIView to call some methods of the controller. I think it would be better to have a delegate concept instead of making a reference to my UIViewController in the SubView, right?
My question is, isn't it possible to do something with my UIScrollViewDelegate. My UIViewController is implementing some delegate methods because my SubView is a UIScrollView. So would it be possible to add a custom method which I can call with something like:
[self.delegate myCustomMethodOnUIViewController]
Or what would be the best way? Should I set up a protocol and add it as custom delegate to my UIViewController? Do I have to set up then a delegate property on my subview?
Thanks for help!
Andy
If you're adding the UIView as a subview to the UIViewController and you want to execute some methods from the superview in your subview there may be some mistake in your software design.
If there's a necessity to do it, then use the #class variable for circular inclusions and call your methods. To read more about #class directive.
http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objectivec/Chapters/ocDefiningClasses.html
More illustration can be read at the link:
#class vs. #import
You can make it work with delegates and protocols, but make sure you handle memory properly within the same contexts to avoid leaks.

Objective C View to Controller Communication

What is the proper way to accept user input in a view and then transfer it to that view's controller? I know the NotificationCenter is one option, but surely there is a more elegant way to transfer data from a view to its controller?
All help is greatly appreciated and I always accept an answer!
Use the delegate protocol design pattern, or target-action by subclassing UIControl. Think about how a UIButton tells a view controller that it's been pressed. In interface builder, you connect an action - a selector something like touchUpInside: to a target - the view controller that owns it. In non-IB, you directly tell the UIButton what selector and what target to use.
Both methods make sense in different cases. For a UITextField, for example, it makes more sense to use delegation because it's possible for the text field to send you any number of events, such as an event when the user begins editing, ends editing, or types a character.
For a button, it makes more sense to use target-action because there's really only one event expressed in different forms.
For swipes and drags and other gestures, use UIGestureRecognizers.
You're looking for Delegation or a Data Source. You can see more information about this here, Delegation and Data Sources
A brief example of this would be, something along the lines of this:
//MyViewSubclass.h
#protocol MyViewSubclassDelegate
//Implement your delegate methods here.
-(void)didTouchView;
#end
#interface MyViewSubclass {
id<MyViewSubclassDelegate>delegate;
}
#property(nonatomic,assign)id<MyViewSubclassDelegate>delegate;
Of course, #synthesize your delegate in MyViewSubclass.m
Now in the class's header, that you want the delegate of MyViewSubclass to be, you need to conform to the `MyViewSubclassDelegate Protocol.
#import "MyViewSubclass.h"
#interface MyViewController : UIViewController <MyViewSubclassDelegate>
In your #implementation of MyViewController., implement the MyViewSubclassDelegate method of -(void)didTouchView.
When you initialize and create your MyViewSubclass object, you set MyViewController as the delegate:
myViewSubclass.delegate = self // Self being MyViewController.
In your MyViewSubclass, when you're ready to forward any information, or simply want to fire a method you would do [self.delegate didTouchView]
Hope this helps !
You are looking for delegation, where the controller set itselfs as the delegate of the view. You know it from UITableViewDelegate.
Make your view a subclass of UIControl and implement the target/action design pattern - use the sendActionsForControlEvents: method to message the controller.
Often the UIKit objects like UITextField have delegate methods that you can implement to perform your business logic. E.g UITextField has a delegate method called - textFieldDidEndEditing: that gets called after the user has dismissed the keyboard.

Descendant as an parent's delegate

Lets say I want to create my own text view with maximum characters constrain. And I want to do that constrain in level below - in text view.
I think of creating CustomTextView : UITextView where customTextView.delegate would be the same object - customTextView (self.delegate = self). The definition of the class would be CustomTextView : UITextView <UITextVIewDelegate> and I would implement – textView:shouldChangeTextInRange:replacementText: to do the constrain logic in.
But somehow this do not work. Can I get explanation why or what can be wrong and how to achieve my intent?
If you are subclassing UITextView, why would you need to set itself as the delegate? The delegate is only used to notify code outside of the UITextView that something changed in the UITextView. This means that the UITextView is notified of changes to itself first and, using the delegate, you can notify external code (UIViewController, etc.) of what happened. If you are subclassing the UITextView, it should receive those change notifications from the OS.
However, looking through the documentation, I cannot see how you would track the built-in events by subclass alone. Here's an article I found with a Google search: Subclassing a UITextView

When should I use a UIViewController in IOS Programming?

I've been looking at the API for IOS Programming, and have been reading about view controllers and UIViews. It looks like UIViewController subclasses are really useful for Modal navigation and custom animation, but I can't see any other uses than that.
What is the benefit to using a UIViewController subclasses rather than a normal NSObject subclass?
Why
#interface MyViewController : UIViewController {
}
-(void)handleEvent;
#end
Instead of just
#interface MyViewController : NSObject {
UIView* view;
}
#property(retain) UIView* view;
-(void)handleEvent;
#end
Don't you just end up adding just the view to the window, not the actual viewController itself?
For most purposes, isnt all of the functionality you need encapsulated within the UIView object?
You just end up adding it like this:
[window addSubview:myViewControllerInstance.view]
Is there a use for UIViewController other than built in functionality like Modal Navigation?
Thanks.
(Sorry if this is a stupid question, I've been learning this for 2 days now)
Cocoa on Mac OS and iOS make heavy use of the Model-View-Controller (MVC) pattern. Following the MVC model, UIViewController is a Controller class. Its job is to coordinate interactions between your user interface (View objects) and your application data (Model objects). More basically, the Controller is primarily where you place your application's logic. It handles events and calls upon the view and model accordingly.
See the UIViewController reference, which has a nice overview on the class.
By deriving from UIViewController, you get a bunch of Controller functionality for free, such as loading views from a Nib file (initWithNibName:bundle:) and responding to view-related events (viewWillAppear:, viewWillDisappear:). Additionally, UIViewController is itself a subclass of UIResponder, which contains functionality for handling touch events (touchesBegan:withEvent, touchesMoved:withEvent, touchesEnded:withEvent).
Basically, there's no reason NOT to use UIViewController with all the functionality it provides. Even if you could manage to to do so, it would be way more work, for no real benefit.
Take a look at the properties and instance methods of the UIViewController Class, which you would not get for free if you just subclassed NSObject. There is a lot of stuff in there that you will use in all of your applications.