I've been working with this
objc_property_t *properties = class_copyPropertyList([NSString class], &outCount);
which has two limitations that I don't know how to resolve:
It doesn't list inherited properties.
I can't differentiate IBOutlets from other properties.
How can I dynamically list all the IBOutlet properties in a class (or instance)?
IBOutlet is #defined as a blank string; it doesn't have any effect at either compile or run time. Its sole purpose is to allow Interface Builder to look at header files and see which ivars should be used as connections. The only way for you to determine which ivars were declared as IBOutlets would be to likewise do some text processing of the header file of whatever class you're working with.
For the properties, I'm not sure there's any other way than going up the list of superclasses and getting all their properties too. You can call class_getSuperclass in a loop to get the whole ancestry of your class;* the function returns Nil when you call it with the root class (NSObject) as the argument.
*See, e.g., this SO answer of mine.
from what I've read this is not possible. The reason is that IBOutlet is a macro that resolves to nothing. So there is nothing in the compiled app to detect. It is used by interface builder which looks at the raw source code where it can see it.
Related
I have imported an Objective-C library with its entire source code in my Xcode project. The recommended way of using this library is to subclass its main object and customise its behaviour. The problem is that this superclass has many properties declared in the .m through the well known mechanism:
#interface BGRichTextEditorViewController ()
#property (strong) NSString *theString;
#end
This way, they are invisible by my subclass, and all I can do is either change the code of the library and move the properties to the .h or use valueForKey to access the superclass properties from the subclass. Is there a more elegant way to solve this ? Many thanks
That is a class Extension. The public interface is in the header file, and the private properties are hidden from you. It is by design by whoever wrote the library.
If you work around this with valueForKey you might very well find your code breaking on a new release of the library (They are usually private for a reason).
If you have the source code and don't need to be on the bleeding edge release, I would simply fork the library and make your own changes.
I created Constants.h and Constants.m as suggested here:
Constants in Objective-C
Now I want to also use some strings defined in Constants.h in Interface Builder to for example set the text of a label.
How to do this using bindings? I think I should somehow use an ObjectController (Mode: Class, Class Name: Constants)? But what would be the Content Object for this controller (since I don't have any variable of type Constants)? Maybe use a Singleton in Constants.m? Any suggestions?
I don't think you can bind the strings in any way.
I would recommend do it in code in viewDidLoad.
Note that string constants aren't so great for texts in UI.
EDIT:
Xibs have their own localization system but I don't think it's very good. It basically means creating a new xib for every language. If you support only one language, just put your strings into the xib and the problem is solved.
NOTE: the following is an idea for my current project and I haven't implemented it yet but I suppose it would let us easily add new language translations.
My idea for a better xib localization is to define IBOutlet for every localizable component (e.g. myButton1, myTextField1) and then write a file with localized strings (xml, properties, plist whatever) where every string is keyed by the IBOutlet name, e.g:
myXib1.myButton1.selected.title = This is a button.
myXib1.myTextField1.placeholder = "This is text field placeholder"
Then, you have to write a method which takes the xib name, finds current language and goes through all string properties for the given xib. It can use [NSObject performSelector:] to access the IBOutlet getters:
id localizableView = [self performSelector:NSSelectorFromString(#"myButton1")];
and you call this method from viewDidLoad (or you create a UILocalizedController class which calls it automatically and all your controllers will be its descendant).
Also note there is NSLocalizedString class which should help you with localization.
While specifying an instance variable that provides a connection between the view controller and the View, we use the IBOutlet keyword prior to the View object type. This helps indicate that it is an instance variable connecting to the View.
However, is there a scenario where I would not require the IBOutlet keyword preceding my view Object type? For example: can we have a scenario where a:
UIButton *display ;
has some kind of use vs
IBOutlet UIButton *display ;
This question stemmed out of curiosity.
Another question that I have probably has to do with understanding the nuances of interfaces and C in general.
In the view controller or any controller as such, we tend to "import" the header files and not the implementation files. I am at odds with this concept and again it is just a curiosity?
The "IBOutlet" keyword doesn't change anything about your program, it just allows Interface Builder to recognize what connections are available. If you don't need to connect something in your interface (for example, if you just want an instance variable for private storage, or if you want to use an #property), then you don't have to use IBOutlet.
We import header files just so the compiler knows what classes and methods are available when using them from other places in the program. An implementation file doesn't need to be imported; it only needs to be compiled into the program and the things it contains will be available.
To the compiler, IBOUTLET is a null operator. It means nothing. It's only purpose is to tell Interface Builder that you intend to connect it to an interface object.
Header files define the interface, and that's all the other class implementations need.
Joe
IBOutlet and IBAction helped Interface Builder detect what outlet and actions you wish to connect to your UI controls, at compile time these IBOutlet and IBAction are ignored and have no use.
I believe you don't need these keywords anymore in Xcode 4.0+.
You can have a scenario where you don't need IBOutlet or IBAction, when you are building UI controls programmatically (in code).
My understanding of IBOutlets is that they act as a marker to ivars and properties in Objective-C classes. Is there anything in the Objective-C runtime that would allow one to query whether an ivar or property or a class has been marked with an IBOutlet at runtime? Or does XCode just do something clever with these at compile time?
If they are a runtime construct, is it possible to define ones own markers and use them in this way:
#private
MyMarker MyClass instance;
It is my understanding that Interface Builder simply reads the header files. IBOutlet and IBAction are trivial #defines:
#define IBOutlet
#define IBAction void
that do not affect the compile at all. Interface Builder reads your header files directly (it is notified by Xcode when the header files change, but it just reads and parses the header files itself.
When the nib files are dearchived, the values are set using the ivar or property through the normal interface, but nothing special is noted that the ivar/property is usable by Interface Builder.
So no, the existence of the IBOutlet/IBAction property is not stored and cannot be accessed, nor can you add your own properties.
You could look at attributes and see if there is anything useful that could be attached to the ivar with an attribute, but I'd be very surprised.
Yes, IBOutlet and IBAction are just thrown away by the parser at the precompilation stage, so there's nothing in the compiled output. And as noted above, they're just textually processed by Interface Builder so that it knows what subset of properties/methods to make available to the connections window.
However, that doesn't stop you doing the same thing yourself - you could just define some #define that are compiled away by the preprocessor, and using textual processing manipulate them. But none of these are available at runtime, which means that you can't really do what you propose.
It's technically possible to write a macro that would do some manipulation of a property/ivar and then add extra information to a different ivar; for example:
#define OUTLET(type,name) type name;BOOL property_##name;
#interface Foo : NSObject
{
OUTLET(NSString*,foo);
}
#end
would expand to
#interface Foo :NSObject
{
NSString* foo;
BOOL property_foo;
}
#end
and you could then use the existence of property_foo to do something with your code (which should be detectable at runtime as well as compile time).
I wouldn't recommend trying to do this generally though ... for a start, it will make your interface (and therefore memory objects) larger than they'd need to be. You'd be better off creating your own class (or struct typedef) to hold the additional information you want.
Can someone explain in an humanly understandable way what an "Outlet" is?
It's an instance variable that shows up in Interface Builder, so that you can use IB to plug another object into the outlet.
When you load the nib, the nib-loading system will do the requisite magic to make sure the right object shows up in each outlet.
Edit: I'd intended to write a full blog post around this image (I changed my mind after finishing the image), but even alone, it should help clarify outlets for people. Here you go:
(source: boredzo.org)
From a code point-of-view and IBOutlet is only a hint for Interface Builder. It's actually a macro that compiles to, well, nothing at all. That is, the compiler completely removes when compiling.
But Interface Builder can scan your code for IBOutlet so when you right-click on an object in IB you can see all the outlets that you could connect to other objects.
alt text http://img27.imageshack.us/img27/5512/picture820090228.png
In this example, delegate is a member variable of UIApplication and it is an IBOutlet too.
I just think of it as a pointer to a UI control. Once I made that mental connection in my mind, it made sense.
I would say they are the bridge that connects your user interface objects to the code that uses them. Like the name suggests, they provide a spot to "plug in" your UI to your code.
The IBOutlet keyword is defined like this:
#ifndef IBOutlet
#define IBOutlet
#endif
IBOutlet does absolutely nothing as far as the compiler is concerned. Its sole
purpose is to act as a hint to tell Interface Builder that this is an instance variable that we’re
going to connect to an object in a nib. Any instance variable that you create and want to
connect to an object in a nib file must be preceded by the IBOutlet keyword.
IBOutlet is a symbol that indicates to Interface Builder that an object instance variable delcared as
IBOutlet id ivar_name;
should be presented as an outlet of an instance of the associated class. This allows you to graphically connect objects in Interface Builder such that, after the NIB is loaded (i.e. when the object is sent an -awakeFromNib message), the value of ivar_name will be a pointer to the object you selected as the outlet's value in Interface Builder.
From the Objective-C language standpoint, IBOutlet means nothing.
An outlet is an instance variable in your code (in X-code) that can be assigned a reference to a user interface object (in Interface Builder). You plug the user interface object into the instance variable. The assignment is specified in the NIB file created by Interface Builder.