I'm trying to create a method that can be called from any object that has a property backgroundColor. Should I subclass NSObject and add a class method or is there a different way to do something like this, that doesn't require adding a category for every object.
Something along the lines of:
[self.myLabel addAwesomeLayerWithSomeColor:(UIColor *)color];
[self.myView addAwesomeLayerWithSomeColor:(UIColor *)color];
[self.myButton addAwesomeLayerWithSomeColor:(UIColor *)color];
Looks like you want this method to be usable on views and subclasses of views. The correct thing to do would be to make a category on UIView. Then, all of these subclasses and any others will be able to use this method.
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'm trying to add custom properties to the UIView so I can use them among all UIView objects and all the UIView's subclasses, like UIImageView, UISlider ... etc
I've tried to use Category to do so, but it turns out I can't use instance variables in the Categories' properties. So, I canceled this solution.
I, also, have tried to use Inheritance to do so, as if I made UIView subclass and added all the properties that I want to. But in this case I do get my additional properties for all of my custom class instances, but I don't get them for any of the other UIView subclasses, like UIImageView.
I'm trying to figure it out but I couldn't.
At the end, I figured a solution to my problem. I'm not sure if it was the best one but it does work for me.
I've used a runtime feature of the Objective-C 2.0 which called: Associated Objects.
This feature gives me the ability to add custom properties to any class using Categories.
I found those resources helpful:
• http://nshipster.com/associated-objects/
• http://www.youtube.com/watch?v=VxUjilPe5Do
I've written a category for UIImagePickerController which I would only like to be accessed by one specific class. The category contains overrides for two private methods. The problem I'm having is that no matter how I try to define the category it seems that every class that instantiates a UIImagePickerController will override these methods. From my understanding this is the expected behaviour when creating a category, but is there any way around it?
I've tried defining the category in a separate .h/.m file as well as adding it directly to a separate class's implementation but neither seem to work. I've also tried creating an additional category which calls super for these methods but the original category still seems to take priority.
Any ideas or is this just not possible?
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
I am learning to program the iphone and I wanted to do some drawing. I followed some example code and subclassed the viewcontroller and it worked fine. Now as I wanted to expand the program I came upon a design question that I could use a little help on.
I subclass myviewcontroller with mynewview. If I have any code in the myviewcontroller how do I call or reference it in mynewview and vice versa? I am not sure if I am asking this right but I am trying to understand the relationship between the class and subclass.
Objective-C objects benefit from inheritance. All classes are subclasses of NSObject, therefore you can call init on any object. If you created a custom class and gave it a method doSomethingAwesome, you are free to then implement doSomethingAwesome in any subclass of your custom class. However, declaring a method in a subclass does not add that method to the superclass. As an aside, I rarely find myself subclass sing my own custom classes. I believe that it is encouraged to maintain what is called a shallow object hierarchy. Usually I subclass the stock cocoa classes, customize to my needs and if I need custom methods in more than one subclass I will declare a category on the superclass rather than relying on inheritance to provide my custom behavior
The messaging system in Objective-C is dynamic. Every object includes a struct with information that the runtime use for introspection. Here the runtime will find a list of methods the object is able to respond. So, let's say you message an instance like this:
[mynewview someMethod];
The runtime will first check the object information to trying to find some method that will be able to respond the message. If nothing is found, then will query the super class, and so on. In fact, the runtime is much more complex, and will give any object more opportunities to respond (that's the dynamic part. For instance, mynewview might not have any method called someMethod and yet, might be able to satisfy the call, but that's something you might not want to worry right now).
From a child class you can call the superclass implementation of a given method with the keyboard super, so if mynewview is a subclass of myviewcontroller you can call myviewcontroller implementation from mynewview with:
[super someMethod];
If someMethod is both present in myviewcontroller and in mynewview, the runtime will automatically only call the child implementation, you have to call the parent implementation (if you have to) from the child implementation.