IBInspectable and protocols - ios

I'm using new Xcode 6 feature called "LiveRendering".
As i need to use some inspectable properties a lot on different custom views, i want to declare them in protocols.
For example :
LiveRenderingTextAttributesProtocol (that declares inspectable properties for textColor, textSize
LiveRenderingBorderAttributesProtocol (that declares inspectable properties for borderStyle, borderColor, borderWidth)
etc ...
After that, each custom view implements the protocols it needs.
But i can't see my inspectable properties on InterfaceBuilder "Attributes inspector" column :/ The LiveRendering is working well when I define the values for these properties as "Used Defined Runtime Attributes", but i want to see them in my Attributes inspector column.
An idea to solve this problem please ?

A protocol defines a set of optional or required methods and attributes to be compliant with, but it's the class the responsible for implementing them. To be able to have reusable base IBInspectable properties you could have a superclass like MyInspectableView that has those properties declared and implemented, so you can subclass it and have those IBInspectables shared between all of them.

Related

Why can't interface builder use a concrete generic subclass of of UIView?

First things first... this has been voted to close as a duplicate of why you can't use Generics directly in Interface Builder. The TLDR answer there is IB uses Objective-C and Objective-C doesn't support generics. That and there's no way to specify a generic's 'specialty' (i.e. what type it uses) anyway. That's understood and makes complete sense.
This question however is about why you can't use a subclass of a fully-defined/specified generic, which again, fully defines that generic's specialty so IB doesn't need to know anything about generics or even that a generic is being used in the first place.
Consider the following class...
class MyView : UIView
{
}
We can easily use this class in Interface Builder by dragging out a view, then changing its class type to be MyView. When instantiated, MyViews init-with-coder is called as expected.
Now consider these classes...
class MyGenericView<T> : UIView
{
}
class MyView : MyGenericView<String>
{
}
In this case, even though MyView is based on the concrete type MyGenericView<String> which itself is based on UIView, you can't use this class in Interface Builder. But why? This is a fully-qualified class that is a subclass of UIView, but the application warns that it cannot find the specified class.
Of note, and to clarify my question, it's my understanding that MyView here is not a Generic. It's a fully-defined concrete type that can be instantiated directly from its class-name and is ultimately based on NSObject (via UIView) so it would seem it should be fully compatible with Objective-C/IB, but that doesn't appear to be the case. I'm trying to understand why that is because it's my understanding that Generics are a compiler feature, not a runtime feature meaning they get compiled right down to non-generic objects, but I could be wrong.
So... is this a bug? If not, can someone shed some light on exactly why this particular scenario doesn't work as expected, addressing the compiler/runtime observations I mentioned from a technical perspective?

IBInspectable property set at design time not keeping value

We are in the process of implementing IBInspectable into a large app in hopes of allowing some settings to be set in Interface Builder to reduce the amount of code in our views. I don't have much experience with IBInspectable/IBDesignable and am looking for some answers and/or clarification on what I'm doing wrong.
I have declared a property in a UITableViewCell subclass as follows:
#property (nonatomic,strong) IBInspectable UIColor* backgroundColor;
When declaring the property like this, I get an option to set that color in Interface Builder > Attributes Inspector, which is to be expected. However when I set the color, the value for _backgroundColor is nil at runtime.
[_labelLoginBackground setBackgroundColor:_backgroundColor];
Could someone clarify what might be going here? Thanks!
UITableViewCell is a subclass of UIView, which already contains a property named "backgroundColor". Do 1 of the following:
Rename your own "backgroundColor" property to "loginBackgroundColor" and start debugging from there.
OR
Do not create a redundant property. Set the background color using the selection widget that is already present in Interface Builder before you ever add IBInspectable.

What is key Path in user defined runtime attributes?

I have inherited a project and i'm confused on what a certain key is.
My question is, what is the styleName key Path ? is it a property to the view ? How can i find out what key Paths are available ?
For example, after i select a UILabel from the storyboard i check the identity inspector and in the user defined runtime attributes i see the following:
I have tried opening the main-styles.plist file but not sure how its linked together.
when i click on the attribute inspector (while still keeping the UILabel in the storyboard highlighted) this is what it looks like:
There is an NSKeyValueCoding protocol, which many of the objects within UIKit conform to.
One of the methods within NSKeyValueCoding is valueForKey: (and many other relevant methods, check the documentation I linked).
By calling valueForKey: on an object, we can, at run time, access properties that were set on the interface builder.
So, for example, on this label, I might do something like this:
Objective-C:
NSString *style = [myLabel valueForKey:#"styleName"];
Swift:
let style = myLabel.valueForKey("styleName")
Now I can grab the value set through the Interface Builder and at run time, I can do something with the label based on what value was set here. For example, here, I might use the particular "style name" to design the label in a particular way.
If you search the project for valueForKey or "styleName", you will likely find where this property is being used and what's being done with it exactly.
To follow up about my question regarding the Attribute Inspector, as of Xcode 6, we can use the #IBInspectable property to create properties which will show up in the Attributes Inspector (as seen here). Consider this UIView extension:
extension UIView {
#IBInspectable var borderColor : UIColor? {
set (newValue) {
self.layer.borderColor = (newValue ?? UIColor.clearColor()).CGColor
}
get {
return UIColor(CGColor: self.layer.borderColor)
}
}
}
Now if we take a look at the Attributes inspector for any UIView (or subclass) in our storyboard, we'll see this:
We now have a "Border Color" property available via the Attributes Inspector which isn't ordinarily there. The reason I point this tool out is because whenever you set one of these properties via the Attributes Inspector, the value you set is actually stored as one of these "User Defined Runtime Attributes":
And whenever this view is loaded from the XIB in my app, one of the first things that will happen is that my borderColor property will be set to this red color I've selected in the Interface Builder.
Below is a list of the available attribute types and the corresponding property type.
Boolean – BOOL (true/false)
Number – NSNumber * or any numeric scalar, e.g. NSInteger
String – NSString
Point – CGPoint
Size – CGSize
Rect – CGRect
Range – NSRange
Color – UIColor
Based on the Apple doc
Use user defined runtime attributes to set an initial value for objects that do not have an interface builder inspector. For example, if you add the following entries in the identity inspector for a custom view:
The custom view will get this message when the nib is loaded:
[customView setValue:[NSNumber numberWithBoolean:NO] forKeyPath:#"isDataLoaded"];
[customView setValue:#"Hatha" forKeyPath:#"excersize.yoga"];
[customView setValue:nil forKeyPath:#"myData"];
Important: The property or key path for the user defined runtime
attribute must exist in the object otherwise an exception will occur.
Because those methods are called when the nib is loaded. So, those runtime attributes can be obtained inside the -(void)awakeFromNib.
For example,
- (void)awakeFromNib
{
// #property (nonatomic) BOOL isDataLoaded, which is assigned by the above `User Defined Runtime Attributes` picture.
BOOL isLoaded = self.isDataLoaded;
}
thanks nhgrif. Actually thanks to your answer which was great so plus one i found whats happening. They created a global category on UIView. its called UIView+mystyle. there they have a method with the following signature:
- (void) setStyleName:(NSString*) styleName
so xcode uses this method without the 'set' and matches it to the runtime key path attribute. in this method they are applying the attribute.

Custom Delegate for a custom View

I m using Xamarin for iOS and I have a custom View which inherit from UIView.
I would like to add a custom delegate to that view.
So far I found that:
Delegate (not useful) example
I want my delegate to be on his own and won't inherit from any other known delegate.
There is no delegate property on UIView (see Apple docs). It does exists in some subclasses, like UITextView (and other types).
What you can do (beside using the base classes provided) is:
(with the unified API) create your own classes that implements the IUITextViewDelegate interface and assign it to the Delegate property;
Create any class that conforms to the delegate (i.e. minimally all required members), add the required [Export], and assign it to the WeakDelegate property.

How to make My UIControl subclass as superclass of programmatically created UIElements?

In my application I want to associate NSMutableDictionary to all UIElements (UIButton, UILable, etc), I can easily achieve this by subclassing each element, but I just want to know if I can make my own UIControl subclass -with a property of type NSMutableDictionary-, as superclass of all programmatically created UIElement s in anyway, so that I can reduce the number of subclasses.
Here like this
#interface UIControl : MyControls
{
}
#property(nonatomic,retain) NSMutableDictionary *details;
#end
and make MyControls as superclass of all programmatically created UIElements
You can do this, not by subclassing, but by adding your own properties and methods to UIControl itself (the superclass of UIButton, UILabel, etc.). These will then be inherited by any standard buttons, labels, etc. that you instantiate. Objective-C lets you add your own methods very easily using Categories. However, you can't add instance variables via categories. To do that, you need to use Associative References which are documented in the Objective-C Runtime Reference.
There's a good tutorial on how to do this here.
By the way, I don't necessarily disagree with inturbidus. But if you're sure you want to go this route, that's how you'd do it.

Resources