I have a custom object, it inherits from NSObject. This object does "some things", one of it is creating an UIView with some UIKit objects (UILabel, UIButtons ecc ecc...). This object has some properties like: textColor, font, backgroundColor... that are used to customize the appearance of the contained UIKit objects.
I would like to customize this properties "one shot" for all created instances of this object, and I've looked at the UIAppearance protocol.
Standard UIKit objects already conforms to UIAppearance protocol, but I don't want to apply the style on ALL UILabels or UIButtons. I want to apply styles only to the UILabels and UIButtons contained inside my object instances. Moreover, I can't (and I don't want) use appearanceWhenContainedIn: because the developer using my custom object may not know what kind of objects are "contained" inside it.
So, I was looking at how to make my custom object conforms to UIAppearance protocol.
AFAIK it must implement the
+ (id)appearance
method. This method should return a proxy object where you can send all your customizations. But, looking at the appearance method of UIKit objects, I see that a private object is returned. An object of class _UIAppearance.
So, it seems that Apple doesn't give me a standard proxy object for customizing my own, and I have to create if from scratch. Is it right or I'm loosing something?
Thanks
Nice implementation, I slightly modified the code and created the class as a subclass of
NSProxy
. Using it in a project I found a memory leak:For example: using the proxy to set global settings/appearance, each instance of that class will never reach refCount 0, so
dealloc
will never be called.Leak code:
Fix:
Copy category for NSInvocation
After some reserach I "give up" about using a standard Apple object. It doesn't exists, for now. I've created my own proxy, it's quite simple (works only with "appearance:" by now).
Let's explain it. I want to set the appearance of "textColor" on a NSObject subclass, let's call it "FLObject". Make FLObject conforms to UIAppearance protocol and override the appearance method. In this method, you should return a proxy class (the one I created):
How it works? FLAppearance creates a single instance of itself for each class passed by the appearanceForClass: method. If you call it two times for the same class, the same instance is returned.
Then, you can do something like this:
FLAppearance overrides the forwardInvocation: method, so it accepts all methods sent. Then, it puts all invocations in an array. When FLObject is initialized, a simple call to
will start to send invocations and set the appearance. Sure, this needs some tuning and error checking, but I think it's a good start.
For the purposes of my own project, I collect everything together and released custom UIApperance proxy as open source project MZApperance
Check out http://logicalthought.co/blog/2012/10/8/uiappearance-and-custom-views
Basically you just need to tag your properties with
UI_APPEARANCE_SELECTOR
and everything works as long as your class is a subclass ofUIView
which will handle the actual vending of the private_UIAppearance
class.Edit:
You're probably better off just rolling your own solution using a singleton and some class methods rather than attempting to do something scary with the runtime. It doesn't look like
UIAppearance
supports your use case.On the other hand, you could stick each object you vend in a private
UIView
subclass and then vend instances of that subclass instead. Then you can forward appearance messages sent to yourNSObject
to the instances you vend and useappearanceWhenContainedIn:<your private subclass>
. That could get messy though and could be confusing for consumers of your class.