Ian's answer is great ... but "messages are sent to the freed instance" can still happen. I solved this problem using the "self" assignment.
So, if you use ARC, you will have to enable this self. (read https://blog.compeople.eu/apps/?p=142 for more information)
To achieve this in your ARC project, add the flag compiler option '-fno-objc-arc' to your file. Then do NO-ARC encoding in this file (e.g. noalloc setting noils, calling super dealloc, etc.)
In addition, the nib client view controller must use a strong property to store the instance returned by awakeFromNib. In the case of my sample code, customView is referenced as follows:
@property ( strong , non-nuclear) IBOutlet CustomView * customView;
Finally, I added some other improvements to the handling of properties and loading of nib using copyUIPropertiesTo: and loadNibNamed defined in my UIView + Util category.
So awakeAfterUsingCoder: code now
#import "UIView+Util.h" ... - (id) awakeAfterUsingCoder:(NSCoder*)aDecoder {
Category Code UIView + Util
@interface UIView (Util) +(UIView*) loadInstanceFromNib; -(void) copyUIPropertiesTo:(UIView *)view; @end
along with its implementation
#import "UIView+Util.h" #import "Log.h" @implementation UIView (Util) +(UIView*) loadInstanceFromNib { UIView *result = nil; NSArray* elements = [[NSBundle mainBundle] loadNibNamed: NSStringFromClass([self class]) owner: nil options: nil]; for (id anObject in elements) { if ([anObject isKindOfClass:[self class]]) { result = anObject; break; } } return result; } -(void) copyUIPropertiesTo:(UIView *)view { // reflection did not work to get those lists, so I hardcoded them // any suggestions are welcome here NSArray *properties = [NSArray arrayWithObjects: @"frame",@"bounds", @"center", @"transform", @"contentScaleFactor", @"multipleTouchEnabled", @"exclusiveTouch", @"autoresizesSubviews", @"autoresizingMask", @"clipsToBounds", @"backgroundColor", @"alpha", @"opaque", @"clearsContextBeforeDrawing", @"hidden", @"contentMode", @"contentStretch", nil]; // some getters have 'is' prefix NSArray *getters = [NSArray arrayWithObjects: @"frame", @"bounds", @"center", @"transform", @"contentScaleFactor", @"isMultipleTouchEnabled", @"isExclusiveTouch", @"autoresizesSubviews", @"autoresizingMask", @"clipsToBounds", @"backgroundColor", @"alpha", @"isOpaque", @"clearsContextBeforeDrawing", @"isHidden", @"contentMode", @"contentStretch", nil]; for (int i=0; i<[properties count]; i++) { NSString * propertyName = [properties objectAtIndex:i]; NSString * getter = [getters objectAtIndex:i]; SEL getPropertySelector = NSSelectorFromString(getter); NSString *setterSelectorName = [propertyName stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:[[propertyName substringToIndex:1] capitalizedString]]; setterSelectorName = [NSString stringWithFormat:@"set%@:", setterSelectorName]; SEL setPropertySelector = NSSelectorFromString(setterSelectorName); if ([self respondsToSelector:getPropertySelector] && [view respondsToSelector:setPropertySelector]) { NSObject * propertyValue = [self valueForKey:propertyName]; [view setValue:propertyValue forKey:propertyName]; } } }