I have a UIButton object in my program.
I want to use it like follows
myButton.setImage:blablabla
mybutton.title:.......blabla
...
...
myButton.placeTextBelowImageWithSpacing:12
While calling my method "placeTextBelowImageWithSpacing:12" it must set the image and text accordingly. I have the method ready with me. How can i use it in the above way.
PS: I hate subclassing.
Thanks in Advance
Create a custom subclass of UIButton. I created a button called FinderButton that has an image and a title centered below it. It works great.
If you hate subclassing then you might want to think about a different line of work.
Being an Objective C programmer that hates subclassing is a bit like being a surgeon who hates blood or a farmer who hates dirt. Defining a class hierarchy is one of the main tools for doing development in an OO language like Objective-C.
You can do this by creating a UIButton category:
UIButton+MyCustomMethod.h
#interface UIButton (MyCustomMethod)
- (void)placeTextBelowImageWithSpacing;
#end
UIButton+MyCustomMethod.m
#implementation UIButton (MyCustomMethod)
- (void)placeTextBelowImageWithSpacing
{
// ...
}
#end
You can't. That isn't valid syntax in Objective-C. The closest you can get to that would be to explicitly declare new properties on UIButton that followed your naming convention. Using them would then look like:
myButton.setTitle = #"something"
Then you could override setTitle's setter (setSetTitle:), and making it call setTitle:forControlState:, which I'm assuming is your goal.
But this should only be done through subclassing (learn to love it, it's a big part of OOP), although if you really really want to, you can add the properties in a category using the Objective-C runtime objc_setAssociatedObject() function more info here: Objective-C: Property / instance variable in category
Related
I have a class that defines all styles on a UIVIew.
They are all predefined but I'm not sure when to fire this.
When I try to create an extension for this:
extension UIView
{
func willMoveToSuperview(newSuperview: UIView?)
{
self.stylize() // Another extension somewhere (not here my problem)
}
}
And I'm getting this error:
Method 'willMoveToSuperview' with Objective-C selector conflicts with
previews declaration with the same Objective-c selector
I have tried to override it, but didn't worked either.
Any ideas on how to be able to apply a same behaviour when all of my UIViews will become visible?
You can use Swizzling technic to customize UIView's function. Take a look at:
http://nshipster.com/method-swizzling/ (objective-c)
or
http://nshipster.com/swift-objc-runtime/ (swift)
Hope that helps.
Even though Swift's Extensions are similar to Categories from Objective-C, what you are trying to do is not allowed in Swift.
You cannot override existing functionality:
Extensions can add new functionality to a type, but they cannot override existing functionality.
Source: Swift Extensions - Apple Documentation
Depending on what it is that you are trying to style, you might want to take a look at UIAppearance, it will allow you to style default colors for the UINavigationBar, amongst other things. NSHipster has a good post about it: NSHipster - UIAppearance
You can create a subclass of UIView with the method .stylize().
Then each view you create, you inherit of you UIView subclass.
You'll be able to cal .stylize() on each UIViewSubclass. Simply write the style code inside the subclass and inherite.
Or
Use a category to add the method to the existing UIView class.
See : https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/CustomizingExistingClasses/CustomizingExistingClasses.html
Outside of swizzling (not generally recommended), or subclassing as noted by David in his answer, there isn't really a way to override existing methods on a class and its subclasses.
One thing you might try is creating a base class for your view controller instead of all your views. In your view controller base class, you could override viewWillLayoutSubviews to recurse through the view hierarchy and call stylize on each view. This means you would be using the subclass approach in fewer places (just view controllers as opposed to all views).
Another thing you might consider if taking the subclassing approach with UIView is that if you are subclassing anyway, you can take advantage of things like #IBDesignable and #IBInspectable to better integrate those UIView subclasses with storyboards and live preview.
I wrote a Swift library which does exactly this, and it works well for the type of styling it seems you want to do: https://github.com/daniel-hall/Stylish
I am using a a library which has quite complicated inherited structure (it consists of a couple of classes, inherited e.g. UITableViewController, UIView, UITableViewCell and others, where some of the classes are used to create custom objects.
I need to add some functionality (to be precise, to implement tap gesture recognizers). The easy solutions is to put a few lines of code into some of the classes of the library.
Generally, I like to have my code separated from libraries code. Is it possible somehow "override" these classes without rewriting them, or to add some extension?
Or the only idea is to write overrides of all the classes generating own classes and tons of useless code?
Or simply add own code to the library?
Additions:
It seems, that categories are right direction, but not particularly, what I want. Here's what I want exactly:
I have a in Class1:
- (void)someMethod {
doThis;
}
And without subclassing // editing the class I would like to transform this to:
- (void)someMethod {
doThis;
andThisToo;
}
Categories add other methods to a class, while I need to add some functionality in already existing method.
You need to use the decorator pattern.
The decorator pattern is used to extend or alter the functionality of
objects at run- time by wrapping them in an object of a decorator
class. This provides a flexible alternative to using inheritance to
modify behaviour.
Since the example you give is pretty sketchy, I can't provide a code example, but check out Wikipedia (http://en.wikipedia.org/wiki/Decorator_pattern)
EDIT
I thought about what you gave and here would be an example of a decorator:
#interface Decorator
#property (strong, nonatomic) id decoratedObject;
- (void)someMethod;
#end
#implementation Decorator
- (void)someMethod {
[self.decoratedObject doThis];
[self andDoThisToo];
}
#end
Recently I've been looking into RESideMenu. What really piqued my interest was his 'UIViewController+RESideMenu.h/m'. It appears to me that this is a way to subclass a UIViewController. It includes IBActions and methods in it that are accessible from anything that inherits from UIViewController.
All of my attempts to replicate this have failed. Is there a special way to go about it?
Usually that sort of classname is used to denote a category. Instead of subclassing it adds additional methods and properties to a class. For more information see here: CustomizingExistingClasses
I’m looking into ways to add a property (an integer in this case) to all UIView instances, whether they are subclassed or not. Is using objc_setAssociatedObject() and objc_getAssociatedObject() within a category the appropriate, Apple-endorsed way to do this?
I have heard some concerns that this constitutes a “runtime hack,” and can lead to problems that are difficult to track down and debug. Has anyone else seen this type of problem? Is there a better way to add an integer property to all UIView instances without subclassing?
Update: I can’t just use tag, because this needs to be used in a code base that already uses tag for other things. Believe me, if I could use tag for this, I would!
Associated objects come in handy whenever you want to fake an ivar on a class. They are very versatile as you can associate any object to that class.
That said, you should use it wisely and only for minor things where subclassing feels cumbersome.
However, if your only requirement is to add an integer to all UIView instances, tag is the way to go. It's already there and ready for you to use, so there's no need for involving run-time patching of UIView.
If you instead want to tag your UIView with something more than an integer, like a generic object, you can define a category like follows.
UIView+Tagging.h
#interface UIView (Tagging)
#property (nonatomic, strong) id customTag;
#end
UIView+Tagging.m
#import <objc/runtime.h>
#implementation UIView (Tagging)
#dynamic customTag;
- (id)customTag {
return objc_getAssociatedObject(self, #selector(customTag));
}
- (void)setCustomTag:(id)aCustomTag {
objc_setAssociatedObject(self, #selector(customTag), aCustomTag, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
#end
The trick of using a property's selector as key, has recently been proposed by Erica Sadun in this blog post.
Use tag. That's what it was meant for.
I'm working on an accessibility project for an iOS application. Because accessibility does not act quite as advertised, I have to override accessibilityFrame, accessibilityActivationPoint and pointInside:withEvent in a subclass in order to expand the region recognized by VoiceOver (for both drawing and touch recognition) beyond the "natural" bounds of the control view. So, in order to change the VoiceOver bounds of a UIButton I have to subclass that class and then add these three methods. In order to do this for a UILabel I have to add another subclass with the code, and so on.
I can refactor the code in these methods to a central location, but I was wondering if this can be done more elegantly with inheritance. I'd like to put this code into a subclass of UIView (maybe called UIViewAccessible) and then create a subclass of UIButton called UIButtonAccessible which inherits from UIButton which would in turn inherit from UIViewAccessible instead of UIView. Is this possible, or can something like this be done with a category?
Edit: According to the docs, you can't really achieve this with a category:
If the name of a method declared in a category is the same as a method in the original class, or a method in another category on the same class (or even a superclass), the behavior is undefined as to which method implementation is used at runtime.
Is there some other way to do this?
To answer your question, no, it can't, since your UIViewAccessible is a second degree sibling to UIButton in the inheritance chain (both inherit from UIView at some point). But I guess you already knew that. As for a solution, you could wrap around your UIView accessible classes a decorator and use protocols for strong typing. That way you'll keep the code in one place. I've described this technique here in more detail (although for a different purpose, it's the same situation).
For the views that would support accessibility you'll have to do this:
#property (nonatomic, strong) UIView<MyAccesibilityProtocol>* view;
//self.view can come from the nib or previously created in code
self.view = [[AccesibilityDecorator alloc] initWithDecoratedObject:self.view];
//you can then use self.view like any other UIView,
//and because it also implements an
//accessibility protocol, you can use the methods
//implemented in the wrapper as well.
//more than that, you can control which methods to override
//in the AccesibilityDecorator class
[self.view addSubview:otherView];//could be overridden or not
[self.view myAccesibilityMethod];//custom method declared in the protocol