Setting a property on a custom object through Interface Builder - objective-c

I have a custom UITableViewController subclass which I use in two places in a nib file. What should I do if I want the two instances to have slightly different behavior? Of course in the code I can select one kind of behavior or the other based on the value of a BOOL, but how do I set that BOOL from Interface Builder, without having to write an Interface Builder plugin?

As of Xcode 6 there is a new way doing this. You can now give your view properties the attribute IBInspectable and then you can edit those properties in IB as you would with and standard view.
So for example:
#property (nonatomic, strong) IBInspectable BOOL
More details (also for the new attribute IBDesignable) in Apples documentation: https://developer.apple.com/library/ios/recipes/xcode_help-IB_objects_media/chapters/CreatingaLiveViewofaCustomObject.html

"User Defined Runtime Attributes" in the Identity inspector is probably what you're looking for. This seems to be new as of Xcode 4.2.
Unfortunately, there doesn't seem to be much (any?) documentation about this feature on the Apple Developer site. I was able to use it for a simple property set.

So far as I know, you can't set parameters in IB without writing an IB Plugin.
That said, you have two other options.
If it is as simple as a single BOOL, you're probably best off making it a property of the MyCustomViewController class and set it in code after you init:
customViewController = [[MyCustomViewController alloc]initWithNibName:#"CustomViewController" bundle:nil];
[customViewController setFunky:YES];
The other option is to create a protocol for a MyCustomViewDelegate. If you're not familiar with protocols, your header would look like this:
#class MyCustomViewController;
#protocol MyCustomViewDelegate
#required
-(BOOL)customViewShouldBeFunky:(MyCustomViewController*)customView;
#end
#interface MyCustomViewController : UIViewController {
NSObject<MyCustomViewDelegate> *delegate;
}
#property (readwrite, retain) IBOutlet NSObject<MyCustomViewDelegate> *delegate;
#end
Since it is an IBOutlet, you can wire up the delegate like any other delegate in Interface Builder.
Then call [delegate customViewShouldBeFunky:self] when you need to determine how your view should behave.

Have two subclasses is probably easier, and will be easier to document.

Here is an example of overriding properties and setting them in custom classes, this may help. The property code will work before awakeFromNib is called. So you may decide what you have to do based on the user's decision right in awakeFromNib.
https://stackoverflow.com/a/31094561/1699210

Related

How should I document property setters?

I occasionally override the setters of Objective-C properties, and was wondering. If I change the default behavior of a method drastically, where should I document this in the header? Or should I just use a new method completely?
In my current case, I am setting a view up as a placeholder view in interface builder. Programatically, there will be a way to replace this view with a new view (Either an icon, or an arbitrary custom view). The method to swap out the placeholder view will automatically set the property to the new view, remove the placeholder view from the parent view, add the new view to the parent view, and reposition/resize the new view appropriately.
I came up with three options:
A) Override the setter of the property, and document along with the property:
// Documentation goes here
// The setter of this property actually does <etc>
#property (nonatomic, retain) IBOutlet UIView* placeholderView;
B) Override the setter, and declare it in the header:
// Documentation goes here
-(void)setPlaceholderView:(UIView*)view;
C) Use a completely different method and set the property to readonly:
#property (nonatomic, retain, readonly) IBOutlet UIView* placeholderView;
-(void)replacePlaceholderView:(UIView*)view;
Option C seems appealing, because it makes it quite clear what the method does. It will also be clear that since it is different than a normal setter, it may act differently (which it will). The disadvantage I see here is that it doesn't seem to follow the normal Objective-C trend.
What do you guys think is the cleanest way to do something like this?
You shouldn't "change the default behavior of a [setter] method drastically" at all. A setter method should set a property, and if it does, you don't need to document the override in the header anywhere, since it does exactly what the user would expect, and the override is an implementation detail that can be documented in the implementation file. Radically changing expected behavior is only going to sow confusion, and is something to avoid. Go with option (C) unless your desired behavior is what a user would reasonably expect to happen when she sets that property.
In practice, an IBOutlet should only be set during initialization from nib files. If I was to refactor this, I'll declare the properties
#property (nonatomic, weak) IBOutlet UIView *initialPlaceholderView;
#property (nonatomic, weak) UIView *placeholderContainerView;
#property (nonatomic, weak) UIView *currentPlaceholderView;
then rename replacePlaceholderView: to
-(void)updatePlaceholderContainerWithNewView:(UIView*)newPlaceholderView;
This is self-documenting code. You can already assume the behavior just by the property and method names.

Proper use of Objective-C protocols

I'm using my free time to play with Objective C. I was reading about Protocols but I'm afraid I might be using it wrong, considering I'm using it the same way (almost the same at least hehe) I do with C# code.
So, here is what I got. I have a protocol, a class manager to weakly couple my views and two views that implement the protocol.
#protocol IView <NSObject>
- (void) loadViewToScreen;
#end
#interface ViewManager : NSObject
#property (atomic, weak) id<IView> document;
#property (atomic, weak) id<IView> browser;
//Singleton
+ (id) getInstance;
#end
Then I call one view the views from each other.
ViewManager *vm = [ViewManager getInstance];
[vm.browser loadViewToScreen];
I'm not interested here what the best way to load views into the screen. It's just a mock code to test protocols.
I could not get the manager to use pointers to the protocols. So I'm afraid I'm getting view copies around. Did I get this right?
Thanks,
Lucas
A protocol, concpetually, is just a part of the type of an object or class. You can't get a pointer to a protocol. (Well, actually you can obtain a protocol object, but that's runtime mocking which doesn't seem to be what you want).
Don't be afraid about getting copies, though. Unless you copy an object or assign it to a copy property, you'll get pointers to the same instance.

Noob properties error

I'm working with an existing code.
Here a popovercontroller has been declared in .h file and its giving me error in implementation line.
.h file
#property (nonatomic, strong) VFImagePickerController *imagePicker;
#property (nonatomic, strong) UIPopoverController *popoverController;
#property (nonatomic, strong) UINavigationController *targetVC;
.m file:
Please suggest how to fix this.
It appears that your class is a subclass of UIViewController. UIViewController has a private, undocumented ivar of _popoverController. Since you are trying to create an ivar in your class with the same name, you are getting an error.
The easiest thing to do is to rename your popoverController property to something different. Otherwise your app might get flagged for using a private API.
This problem occurs because your superclass, UIViewController, already has an instance variable named _popoverController. As a result, neither the default synthesis nor your explicit (commented) #synthesize directive have access to the instance variable that they want to use to provide the popoverController property.
You can resolve this by either renaming your property, or explicitly synthesizing the property to use a different instance variable name:
// Either
#property (nonatomic, strong) UIPopoverController *localPopoverController
// Or
#synthesize popoverController = _localPopoverController;
(Also note that the "local" prefix isn't necessarily best practice for your property names or instance variables; take a second to consider your preferred naming convention and pick a property/instance variable name appropriately.)
Uncomment the synthesize line and remove underscore to look like this: #synthetize popoverController;
And replace every _popoverController var name in your .m file to popoverController
Do not name your instance variable (or property) popoverController. As mentioned above UIViewController has an instance variable declared as _popoverController. (Who knows why.)
It would be wise not to give your popover controller a generic name anyway, because, for example, if you decide to add more than one popover to a toolbar, you'll have to create more than one popover controller to accomplish this.
If you look at Apple's sample code, you can see how they do this:
http://developer.apple.com/library/ios/#samplecode/Popovers/Introduction/Intro.html#//apple_ref/doc/uid/DTS40010436
Check out the private properties section in DetailViewController. There, you will see three controller objects and none with the generic name "popoverController”. That will cause problems.

Objective C - Defining an instance variable when defining a property

I saw this code snippet on the Internet (http://iphonedevelopment.blogspot.com/2008/12/outlets-property-vs-instance-variable.html):
#import <UIKit/UIKit.h>
#interface MyViewController : UIViewController {
UILabel *myLabel;
}
#property (nonatomic, retain) IBOutlet UILabel *myLabel;
#end
My question is...When #synthesize is called isn't the UILabel instance variable created automatically? What is the point of creating the instance variable in the header file.. Can you get away with just the #property?
When #synthesize is called isn't the UILabel instance variable created automatically?
Yes.
What is the point of creating the instance variable in the header file.
Personal preference. Some developers (like me) prefer to see a complete picture of the state of a class. It helps to see what instance variables are available, as well as check that all instance variables are released correctly.
It's also a relatively new feature. Older code wouldn't expect automatically-generated instance variables.
Can you get away with just the #property?
No, you need to #synthesize to get an automatically generated instance variables A property value that's generated programmatically would not map directly to any instance variable.
#synthesize will create the instance variable but you will not be able to see it in the debugger which can be downright inconvenient.
Consider filing a bug with Apple about this.
Yes you can get away with just the #property in Objective-c 2.0.
see: Do declared properties require a corresponding instance variable?

Declaring IBOutlet inside or outside #interface?

sorry If am I being too picky on this one but I am learning iOS programming now and I've seem some people who declare the IBOutlet like this:
IBOutlet attached to property
#import <UIKit/UIKit.h>
#import "CustomCell.h"
#interface CustomTableViewController : UITableViewController {
CustomCell *customCell;
}
#property (nonatomic, retain) IBOutlet CustomCell *customCell;
#end
And some declaring like this:
IBOutlet attached to the declaration inside the interface
#import <UIKit/UIKit.h>
#import "CustomCell.h"
#interface CustomTableViewController : UITableViewController {
IBOutlet CustomCell *customCell;
}
#property (nonatomic, retain) CustomCell *customCell;
#end
which one is the proper way to declare it? Are any differences between them?
If someone know to explain why do they put it on different places it would be awesome to learn.
Thanks a lot :)
Both of those are still "inside the interface" so your title it a bit confusing but I see what you are asking.
In many cases the result of either approach will be the same but they are different. An IBOutlet property will call the property's setter method which gives you an opportunity to override that setter if setting that property should have some side effect.
I prefer to use outlets on properties because I think it makes the memory management of the objects loaded from the nib much clearer. Take a look at memory management of nib objects and I think you will see what I mean.
Objects in the nib file are created with a retain count of 1 and then autoreleased. As it rebuilds the object hierarchy, UIKit reestablishes connections between the objects using setValue:forKey:, which uses the available setter method or retains the object by default if no setter method is available. This means that (assuming you follow the pattern shown in “Outlets”) any object for which you have an outlet remains valid. If there are any top-level objects you do not store in outlets, however, you must retain either the array returned by the loadNibNamed:owner:options: method or the objects inside the array to prevent those objects from being released prematurely.
IBOutlet ivars will call setters for those ivars if they exists and directly retain the object loaded from the nib if no setter is found.
Advertising the property as the IBOutlet at least makes it clear that the property's setter will always be used and follow whatever memory management rule has been set for that property.
Finally I argue that IBOutlets are part of the public interface of a class and it is therefore better to expose methods (via a property) for working with them eager than using -setValue:forKey: to manipulate the backing ivars which should be an implementation detail.
The two styles are interchangeable, there is no difference in the generated code or the way objects will be loaded from a nib. Really.
However, both styles have a redundant line. Simply leave out the ivar declaration. Just the line
#property (nonatomic, retain) IBOutlet CustomCell *customCell;
is sufficient in the modern runtime.
If you have a complex project, I suggest moving all the outlets out of the public interface into a separate header file. Most outlets are private interface, the only reason to have them in a header is so Interface Builder can find them.
You can declare both ways, there is no difference actually.
But, here is the thing:
If you need your class to have some ivar with a special behavior or it has to be accessed from outside, etc, and it has to be a property, then I will say you have 2 options to choose from (attached to the property and inside the class interface).
If that is not your case, don't create a property, is not necessary, just do it inside your class interface.
Hope it helps ;)