An alternative to the #warning(…) tag in Xcode

Experienced old Objective-C developers like myself appreciated the #warning(...) tag in source code. It was a great way to remind yourself of things that might otherwise get lost in TODO comments that you forget to search for or your colleague is unaware of. Then it went away in Swift, and people like this guy came up with his own solution, which I liked for a while because it was truly customizable by keyword. Then Apple put #warning(...) back and that became less of an important thing to use.

…. Until I started working on Source Code that is to become a Cocoapod. For if you try to run pod lint spec MySpec.podspec, and there are compiler warnings, the validation process will fail.

So, return of the Run Script that goes through your Swift files and searches for keywords and adds warnings or errors as appropriate.

You can see the original post, or just create a run script (I think before you compile sources but I don’t think it matters), and add this (modify keywords as you like):

TAGS="TODO:|FIXME:"
ERRORTAG="ERROR:"
find "${SRCROOT}" \( -name "*.h" -or -name "*.m" -or -name "*.swift" \) -print0 | xargs -0 egrep --with-filename --line-number --only-matching "($TAGS).*\$|($ERRORTAG).*\$" | perl -p -e "s/($TAGS)/ warning: \$1/" | perl -p -e "s/($ERRORTAG)/ error: \$1/"


Cheat Sheet – IB_DESIGNABLE Views

Not so much a cheat sheet, but a general procedure to follow. Consider this class, a UILabel that draws an outline around it that you can customize and more importantly, view from Interface Builder:

#import 

IB_DESIGNABLE
@interface HSOutlinedLabel : UILabel

@property (nonatomic, assign) IBInspectable CGFloat outlineWidth;
@property (nonatomic, assign) IBInspectable UIColor *outlineColor;
@property (nonatomic, assign) IBInspectable CGFloat cornerRadius;

@property (nonatomic, assign) IBInspectable CGPoint padding;  // between the text and outline

@end

and then the .m

#import "HSOutlinedLabel.h"

@implementation HSOutlinedLabel

- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
        
        [self _commonInit];
    }
    return self;
}

- (void)_commonInit
{
    // gets called first (initWithCoder:), before any of the settings in IB are used.
    self.layer.masksToBounds = YES;
    _outlineWidth = 0;
    _outlineColor = nil;
    _cornerRadius = 5;
    _padding = CGPointZero;
    self.layer.cornerRadius = _cornerRadius;
    
}

- (void)prepareForInterfaceBuilder
{
    // careful!  this will overwrite any settings in Interface Builder.
    // it's meant for setting values that perhaps aren't IBInspectable
    [super prepareForInterfaceBuilder];
}

- (void)awakeFromNib
{
    if (_outlineWidth > 0) {
        self.layer.borderWidth = _outlineWidth;
        
        if (_outlineWidth > 0) {
            self.layer.borderColor = _outlineColor ? _outlineColor.CGColor : NULL;
        }
        else
        {
            self.layer.borderColor = NULL;
        }
    }
}

#pragma mark - Setters (Are used by Interface Builder)

// NOTE:  Interface Builder calls setValue:forKey: when you change
// an inspectable value.  If you are purely drawing your UIView subclass
// with -drawRect: then these changes update.
// However, if you see the setters below, I use the IBInspectables
// to ultimately wrap CALayer properties.  If you want your view to
// draw correctly,  you need to write accessors for any IBInspectable
// that triggers changes to any object that won't necessarily be done
// in drawRect:

- (void)setOutlineWidth:(CGFloat)outlineWidth
{
    if (_outlineWidth != outlineWidth) {
        _outlineWidth = outlineWidth;
        self.layer.borderWidth = outlineWidth;
    }
}

- (void)setOutlineColor:(UIColor *)outlineColor
{
    if (_outlineColor != outlineColor) {
        _outlineColor = outlineColor;
        self.layer.borderColor = outlineColor.CGColor;
    }
}

- (void)setCornerRadius:(CGFloat)cornerRadius
{
    if (_cornerRadius != cornerRadius) {
        _cornerRadius = cornerRadius;
        self.layer.cornerRadius = cornerRadius;
    }
}

- (void)setPadding:(CGPoint)padding
{
    if (!CGPointEqualToPoint(_padding, padding)) {
        _padding = padding;
        [self invalidateIntrinsicContentSize];
    }
}

- (CGSize)intrinsicContentSize
{
    CGSize size = [super intrinsicContentSize];
    size.width += 2 * _padding.x;
    size.height += 2 * _padding.y;
    
    return size;
}

@end

I just meant this to be a starting point for your own work. And actually a reminder for myself.

IB_DESIGNABLE UIView using a custom CALayer (for animations)

I’m a very visual person.  If I can use Interface Builder, I do.  I like it mainly for the separation of concerns, and really who doesn’t like a WYSIWYG way of inspecting your UI ??

So, I had a somewhat unique scenario in that I want to have a UIView that has a custom CALayer that has properties I can animate.  (See here for some background on that, though I will touch on it below:  https://www.objc.io/issues/12-animations/animating-custom-layer-properties/ )

But I also want to be able to configure these properties in Interface Builder via the Inspector pane.

I found a way to do this, although it’s tedious.  In short, you have to define a custom layer, deal with it’s display and animation, and wrap the layer properties on your UIView subclass.

What?  Fine.  Here’s the simplified code to show you how it would work for something like a custom progress bar:

//  HSProgressView.h
//  Created by Stephen O'Connor on 17/02/16.
//  MIT License.

#import <UIKit/UIKit.h>

IB_DESIGNABLE
@interface HSProgressView : UIView

@property (nonatomic, assign) IBInspectable CGFloat progressValue;  // clamps between 0...1
@property (nonatomic, strong) IBInspectable UIColor *barColor;

- (void)setProgressValue:(CGFloat)progress animated:(BOOL)animated;

@end

And the .m file

//  HSProgressView.m
//  Created by Stephen O'Connor on 17/02/16.
//  MIT License.


#import "HSProgressView.h"

@interface HSProgressView()

+ (NSArray*)customLayerProperties;

@end

// HERE WE DEFINE A LAYER THAT IDEALLY WE'D PREFER TO DO IN
// A UIView SUBCLASS IN drawRect:, BUT TO LEVERAGE THE ANIMATION
// PROPERTIES OF COREANIMATION, WE DEFINE THEM IN A CALayer THEN
// WRAP THEM
@interface _HSProgressViewLayer : CALayer

@property (nonatomic, assign) CGFloat progressValue;
@property (nonatomic, strong) UIColor *barColor;

@end


@implementation _HSProgressViewLayer

// these methods are generated at runtime
@synthesize progressValue, barColor;

+ (BOOL)needsDisplayForKey:(NSString *)key
{
    // HERE WE SAY IF ANY OF THESE PROPERTIES CHANGE,
    // SHOULD IT REDRAW THE LAYER
    
    // I JUST SAY YES FOR ALL OF MY CUSTOM PROPERTIES
    // BUT YOU CAN CONTROL THIS HERE
    for (NSString *propertyName in [HSProgressView customLayerProperties]) {
        if ([key isEqualToString:propertyName]) {
            return YES;
        }
    }
    
    return [super needsDisplayForKey:key];
}


// THIS IS WHERE YOU DEFINE WHICH PROPERTIES CAN BE ANIMATED
// AND HOW.  Duration, timing, etc.
// In our case, we only want to animate progress, but not color
- (id)actionForKey:(NSString *)key
{
    // if (key corresponds to a property name I want to animate...)
    if ([key isEqualToString:@"progressValue"])
    {
        CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:key];
        animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
        
        if ([key isEqualToString:@"progressValue"])
        {
            // LOOK HERE!  It's outlined in that post listed above, but
            // if you animate, you need to look to the presentationLayer
            // as it holds the currentValue *right now* or *on screen*
            // if you didn't call presentationLayer, the progress
            // value is going to be the value you are trying to animate to
            // and you would see nothing!
            
            
            animation.fromValue = @([self.presentationLayer progressValue]);
        }
        
        // other animatable properties  here...
        
        return animation;
    }
    return [super actionForKey:key];
}

- (void)display
{
    // again, takes the value that it currently is animating to,
    // if you called self.progress it would always return the final value.
    
    // that being said, if we want to inspect it in interface builder
    // we have to omit animation and just look at the value it 'wants' to be
    CGFloat progress;
#if !TARGET_INTERFACE_BUILDER
    progress = [self.presentationLayer progressValue];
#else
    progress = [self progressValue];
#endif
    
    
    //create drawing context
    UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0);
    
    // backgroundColor is a property on CALayer, but we still need to draw him!
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(ctx, self.backgroundColor);
    CGContextFillRect(ctx, self.bounds);

    
    // now for our custom properties
    UIBezierPath *path;
    
    CGRect drawRect = self.bounds;
    drawRect.size.width = MAX(0, MIN(1, progress)) * drawRect.size.width;
    
    path = [UIBezierPath bezierPathWithRect:drawRect];
    [self.barColor setFill];
    [path fill];
    
    //set backing image
    self.contents = (id)UIGraphicsGetImageFromCurrentImageContext().CGImage;
    UIGraphicsEndImageContext();
}

@end


static NSArray *HSProgressViewLayerProperties = nil;

@implementation HSProgressView

+ (Class)layerClass
{
    return [_HSProgressViewLayer class];
}
    
+ (NSArray*)customLayerProperties
{
    if (!HSProgressViewLayerProperties) {
        
        HSProgressViewLayerProperties = @[
                                          @"barColor",
                                          @"progressValue"
                                          ];
    }
    return HSProgressViewLayerProperties;
}

#pragma mark - Generic Accessors

// we wrap the properties on the layer, so we override this
// for integration into Interface Builder's IBInspectable properties

- (void)setValue:(id)value forKey:(NSString *)key
{
    for (NSString *propertyName in [HSProgressView customLayerProperties]) {
        if ([key isEqualToString:propertyName]) {
            
            [self.layer setValue:value forKey:key];
            
            return;
        }
    }
    [super setValue:value forKey:key];
}

- (id)valueForKey:(NSString *)key
{
    for (NSString *propertyName in [HSProgressView customLayerProperties]) {
        if ([key isEqualToString:propertyName]) {
            return [self.layer valueForKey:key];
        }
    }
    return [super valueForKey:key];
}

#pragma mark - Public Methods

- (void)setProgressValue:(CGFloat)progress animated:(BOOL)animated
{
    // if animated is yes, it gets it's information about how to
    // animate it via actionForKey: on the custom layer implementation!
    
    if (!animated) {
        [CATransaction begin];
        [CATransaction setDisableActions:YES];
    }
    
    _HSProgressViewLayer *layer = (_HSProgressViewLayer*)self.layer;
    layer.progressValue = progress;
    
    if (!animated) {
        [CATransaction commit];
    }
}

#pragma mark - Layer-backed Accessors

// SADLY WE HAVE TO WRITE A LOT OF BORING CODE HERE TO WRAP THE ACCESSORS.
// IF SOMEONE KNOWS BETTER, PLEASE TELL!
- (void)setProgressValue:(CGFloat)progressValue
{
    [self setProgressValue:progressValue animated:NO];
}

- (void)setBarColor:(UIColor *)barColor
{
    _HSProgressViewLayer *layer = (_HSProgressViewLayer*)self.layer;
    layer.barColor = barColor;
}

- (UIColor*)barColor
{
    _HSProgressViewLayer *layer = (_HSProgressViewLayer*)self.layer;
    return layer.barColor;
}

- (CGFloat)progressValue
{
    _HSProgressViewLayer *layer = (_HSProgressViewLayer*)self.layer;
    return layer.progressValue;
}


#pragma mark - Layout and Drawing

- (void)layoutSubviews
{
    [super layoutSubviews];
    self.layer.bounds = self.bounds;
    [self.layer setNeedsDisplay];  // because the layer follows the size of the view, whose contents fill the view's frame.
}

@end

There it is! Copy-paste this into your own class and try it out in Interface Builder. Now you should see how you can extend this for your own purposes.

Incredibly Useful Way to Print Your Core Data Model

So, I love a good bit of old fashioned Pen and Paper to get my thoughts out.  Maybe it’s that I enjoy just using a pen, the flow of the ink on the page.  (I’m, accordingly, a total pen snob).

Sometimes when I want to analyze a data model, I’d love to have it on paper, just so I can scribble, cross things out, etc, etc.

Until now, I found it difficult to have to deal with the CoreData model editor in Xcode because I couldn’t easily print it out, then I found this gem on stackoverflow.com

Which can be copy-pasted here:

I defined a 1m by 1m paper size, used it to create a PDF, cropped and then printed it:

  • Go to “File”->”Page Setup…”
  • Go to “Paper Size”->”Manage Custom Sizes…”
  • Define a new paper size with 1000×1000 mm and no borders
  • Go to “File”->”Print…”
  • Choose “PDF”->”Open PDF in Preview”
  • Go to “Tools”->”Rectangular Selection”, select the area to crop
  • Do “Tools”->”Crop”
  • Go to “File”->”Print…”, print

Sounds complicated, but works. Instead of cropping, you could use the scale factor in the Preview print dialog.

Proportionally Sized Views, Views that inherit backgroundColor

So, I’m a bit of a late adopter. The problem with working intensively on a project that is grossly understaffed is that you don’t have time to keep up with all the technology. So just now am I getting a deeper understanding of Autolayout on iOS.

There is no way to avoid using Autolayout, so if you haven’t started using it, please do! The various screen sizes of the various iPhones, not to mention multi-tasking on iPad will basically demand you use it.

I’ve run into a situation where I might design some elements for iPhone 5s, but on iPhone 6 they could be bigger. I don’t like the complexity of Size classes, and don’t even think they work very well for the different iPhones. I think it was a way to make one layout work on iPhone and iPad. Hmm… the topic here.

On my latest project I found two things that I needed. So I built them. I wanted a UI Element (a UIView) to always maintain a certain proportion of its superview. Say 75% of the screen width. I didn’t know how to do this in Autolayout. (I suspect it might have something to do with Multipliers??)

Anyway, I also wanted to be able to define a view that would just inherit the background color of its superview. This makes it easier to make changes later in Interface Builder without having to go and alter the whole view hierarchy by hand, or to make outlets for all those views and change them in code.

Well, try for yourself. Here’s the code:

// HSProportionallySizedView.h
//
// Created by Stephen O'Connor on 30/09/15.
// Copyright © 2015 Iconoclasm Spasms. All rights reserved.
// Actually, MIT License. Hack to your heart's content!
  
#import <UIKit/UIKit.h>
  
extern CGFloat const HSProportionallySizedViewNoEffect;
  
@interface HSProportionallySizedView : UIView
  
@property (nonatomic, assign) IBInspectable BOOL inheritsBGColor;  // default: NO
  
// between 0...1.f. Defaults to HSProportionallySizedViewNoEffect
@property (nonatomic, assign) IBInspectable CGFloat widthProportion;
@property (nonatomic, assign) IBInspectable CGFloat heightProportion;
  
@end
//  HSProportionallySizedView.m
//
//  Created by Stephen O'Connor on 30/09/15.
//  Copyright © 2015 Iconoclasm Spasms. All rights reserved.
//  Actually, MIT License.  Hack to your heart's content!

#import "HSProportionallySizedView.h"

CGFloat const HSProportionallySizedViewNoEffect = -1.f;

@implementation HSProportionallySizedView

- (void)willMoveToSuperview:(UIView *)newSuperview
{
    if (self.inheritsBGColor) {
        self.backgroundColor = newSuperview.backgroundColor;
    }
}

- (void)awakeFromNib
{
    if (self.inheritsBGColor && self.superview) {
        self.backgroundColor = self.superview.backgroundColor;
    }
}

- (void)makeDefaultValues
{
    _inheritsBGColor = NO;
    _widthProportion = HSProportionallySizedViewNoEffect;
    _heightProportion = HSProportionallySizedViewNoEffect;
}

- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        [self makeDefaultValues];
    }
    return self;
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    if (self = [super initWithCoder:aDecoder]) {
        [self makeDefaultValues];
    }
    return self;
}

- (CGSize)intrinsicContentSize
{
    CGSize size = [super intrinsicContentSize];
    if (self.superview) {
        
        if (_widthProportion != HSProportionallySizedViewNoEffect) {
            
            CGFloat proportionalWidth = MAX(0, MIN(1, _widthProportion));
            
            if (proportionalWidth == 0) {
                NSLog(@"One of your proportional size values is set to 0!!");
            }
            size.width = proportionalWidth * self.superview.bounds.size.width;
        }
        
        if (_heightProportion != HSProportionallySizedViewNoEffect) {
            
            CGFloat proportionalHeight = MAX(0, MIN(1, _heightProportion));
            if (proportionalHeight == 0) {
                NSLog(@"One of your proportional size values is set to 0!!");
            }
            size.height = proportionalHeight * self.superview.bounds.size.height;
        }
        
    }
    return size;
}
  
@end

You can see that with the default values it behaves exactly like a UIView. So it makes a suitable baseclass in your codebase.

NOTE: I’m sure there’s a way to do the proportional size in Autolayout without this, so please help me in the comments!

Code Police – The Importance of Code Style Consistency

It’s not my intention to talk about which coding style is the best. Everyone has a specific style and their reasons for it.

I do recommend thinking about this topic, and to that aim there is a very interesting tool out there on the market called ObjectiveClean

I’ve enjoyed working with my colleagues on my current project and have a very friendly relationship with my boss. I do however have to chide him from time to time for not sticking to a clean coding style. I joke about being the Code Police. He jokes about keeping me on my toes.

There are certain style conventions that should however be adhered to for the following reasons:
– Conventions create consistency.
– Consistency allows you to make assumptions about how the code is written
– Assumptions allow you to refactor more easily.

What? If for example I have in my codebase the requirement that we write:

someString = @"SomeString";  // note the spaces between the equal sign

I can then easily find strings by searching for = @". You might not think that this is a big deal. You probably haven’t refactored a lot of code.

I spent over one hour refactoring some constants purely because they didn’t follow a standard. Imagine error codes defined like this:

static int const errNotConnected = -1;
static int const errWifiOff = -2;
static int const errFileIOError = 1;

2 absolutely horrible things result by trying to define error codes like this:

i) I provide no context for these error codes. I have no idea what class they relate to, what functionality.
ii) do a find and replace for these. if you put in a Project wide search term “err”… you are going to basically get thousands of results.

Now, the know-it-alls amongst you are going to say something snarky like “well, why don’t you just write a regular expression that will find exactly what you’re looking for?” The answer is practicality. Regex is a bit of Voodoo for most programmers and it’s not exactly pretty syntax despite how powerful it is.

You could just provide a context, and even better, pack these in an enum

typedef NS_ENUM(NSInteger, HSConnectionManagerErrorCode)
{
  HSConnectionManagerErrorCodeNotConnected = -1,
  HSConnectionManagerErrorCodeWifiOff = -2,
  HSConnectionManagerErrorCodeFileIOError = 1
};

From the name alone, I gain a few things:

i) I know which class it relates to
ii) I know what the error was all about
iii) Any time I’m coding I can just type in HSConnectionManager and Autocomplete will give me a list of the enums I’m looking for, so I don’t even need to go digging through header files.

Good habits allow us all to do our jobs more quickly, and make it easier to work with each other’s code. I highly recommend caring about the quality of your work. You can be proud of yourself and others will enjoy coding with you.

My Most Used Code Snippet in Xcode

It’s good to get in the habit of having good habits. 🙂

A lot of people write custom UIView code but then have trouble debugging a few things. Mostly pertaining to writing it to be initialized in code, then they initialize it in Interface Builder. As such, I just use the following snippet and it saves me a lot of boilerplate.

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self configureView];
    }
    return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
        [self configureView];
    }
    return self;
}

- (void)configureView
{
  // common initialization
}

That’s it for today.

Adding Documentation – appledoc

Yes, there have been thousands of posts on this topic. I guess this is more a reference for me, but perhaps it will be useful to you too. That said, this is for Xcode 4.x and Xcode 5 is coming out soon… <sigh>

  • Clone the appledoc repo at:  https://github.com/tomaz/appledoc.git
  • Build the project.  After it completes, in the project navigator, open the Products folder and right-click on appledoc, and Show In Finder.  Copy that file to your /usr/bin folder. (There is some discussion over which folder, read here.  Ultimately it ‘just works’ in /usr/bin)  Do this every time you update the appledoc project.

Documentation is generated in your project by creating a target designed to do this task.

  • Click on your project name at the top of the Project Navigator in Xcode, and you should see the settings screen in the main panel.  Add a Target, of type Aggregate.  Call it Documentation.
  • This target basically needs to do one thing: Run a Script.  So, add a build Phase of type Run Script.  We will come back to this later.

Appledoc can be run completely from a script with command line args, but let’s use a .plist to specify our parameters.  Create a file called AppledocSettings.plist, put it in a folder (relative to your project root) called ‘appledoc’ and copy-paste this into it:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>--company-id</key>
	<string>com.YOUR_COMPANY_NAME</string>
	<key>--create-docset</key>
	<true/>
	<key>--create-html</key>
	<true/>
	<key>--ignore</key>
	<array>
		<string>ThirdParty</string>
		<string>Libraries</string>
		<string>Frameworks</string>
		<string>Testing</string>
	</array>
	<key>--install-docset</key>
	<true/>
	<key>--docset-platform-family</key>
	<string>iphoneos</string>
	<key>--output</key>
	<string>appledoc</string>
	<key>--project-company</key>
	<string>YOUR_COMPANY_NAME</string>
	<key>--project-name</key>
	<string>YOUR_PROJECT_NAME</string>
	<key>--keep-undocumented-objects</key>
	<true/>
	<key>--keep-undocumented-members</key>
	<true/>
	<key>--warn-undocumented-object</key>
	<false/>
	<key>--warn-undocumented-member</key>
	<false/>
	<key>--warn-empty-description</key>
	<true/>
	<key>--warn-missing-arg</key>
	<true/>
	<key>--warn-unknown-directive</key>
	<true/>
	<key>--logformat</key>
	<string>xcode</string>
	<key>--exit-threshold</key>
	<integer>2</integer>
</dict>
</plist>
  • So now that you’ve created that, import it into your Xcode project for easy editing. Don’t add it to any target because it’s just to be visible to us in Xcode, not packaged in any bundle.

You should read up on what the different parameters do, and you can add further parameters that you need by running appledoc –help from the terminal.  Hopefully you should see how these command line args translate to this .plist file.

Go back to the Documentation Target Settings, and now we will provide the script for it to run:

appledoc \
"${PROJECT_DIR}/appledoc/AppledocSettings.plist" \
"${PROJECT_DIR}/PathToSourceFiles"

NOTE: “PathToSourceFiles” is really the path to where you have the source with the documentation you want to have generated.  So this will be specific to your Codebase.

What just happened?  We told appledoc to run with the settings provided in the .plist, and generate documentation for any source located in PathToSourceFiles.  Note in the .plist file above I have the argument “ignore .m” set to YES, since this is private.  If you’ve done your job right (see my posts on the importance of Encapsulation!!) you won’t need to document this source – your comments should hopefully be enough.

  • Build the Documentation target, you’ll see in the Xcode Organizer that your source has been added to the Xcode documentation library.  Awesome!

Actually Writing Documentation

There are two things that will help you writing Documentation formatted correctly for appledoc.  Oliver Drobnik over at Cocoanetics provides an excellent tutorial on this.  (Search for Commenting Correctly).

Using those examples, I would also recommend you create some Code Snippets for Xcode so that you can easily just drop in a template to document a method or a property or whatever.  Here is a link for setting up documentation Code Snippets in Xcode.  With the examples at Cocoanetics, you could create a few snippets for different situations (Method, Property, Class Description, etc) in no time!

I also suggest looking at the AFNetworking Docset in Xcode, and if you want your documentation to look like theirs, just go to that relevant source file to see how they formatted it. AFNetworking is really well documented!

Deleting Docsets

If you look in the appledoc folder where I asked you to place your AppledocSettings.plist, whenever your Documentation is generated, appledoc places a file there telling you where it placed the docset.  You can navigate there and delete any docsets you don’t want to appear in Xcode anymore.  Restart Xcode and this will be up-to-date!

Happy Coding!

UPDATE: Just added some code you can copy-paste to make your own Code Snippets in Xcode. See my github page for that

Why I DO use Interface Builder – A rebuttal

If you are not familiar with this post on why an accomplished Developer does not use Interface Builder, I suggest you read it before reading this post.

I’d like to weigh in on the subject as some of the points shouldn’t – in my view – carry as much weight as maybe he would like them to in that post.  It’s not my intention to start a flame war, but I do have a vested interest in there being programmers who use Interface Builder, and ultimately I think that those who are against it just aren’t yet used to it or have understood what a powerful tool it can be.

Choosing Explicit over Implicit

Choosing to be explicit is my number one reason to do things in code instead … they can see right away where everything is and not have to wonder if this file has a NIB.

If you keep your project folders organized such that a folder has a .h/.m/.xib for your object then this is really a non-issue.

I have spent countless hours searching for the source of a bug only to discover it’s some checkbox in one of the half dozen inspectors in Interface Builder. If it was in code, it’s simple to glance at the view code and see the source of the problem much quicker.

If you like writing a lot of boring code to set properties that you can do in a second (and change later just as easily) then do it.  This is really a matter of style.  Interface Builder is just a part of a toolchain.  I also am a very visual person, so I have a better overview of what’s happening with a NIB.  Most of the time you are dealing with 2 inspectors.  The “I can see it all in code” argument only really applies if you already know what the default properties are supposed to be; so again, you had a learning curve with that.

Tight Coupling

It is much harder to use Interface Builder for reusable views….

I don’t really understand the meaning of this.  I’m starting to suspect that it’s just a matter of experience.  Perhaps part of you just doesn’t want to embrace it?  As an iOS coder, I ‘grew up’ with it, so can’t understand why people don’t want to use it.  (If you want to know how to easily create reusable instances of a UIView from a NIB)

Not to mention, if you use lots of custom views, your NIBs will just be a bunch of invisible boxes. So now you have this tight coupling that is even harder to work with if you were to just lay it out in code.

Did you know about this?  There are a lot of runtime attributes for your custom classes you can set up in IB.  Also, it’s a tool to build view hierarchies.  I don’t know what this argument really is.  I really don’t understand how using IB is any tighter coupling than in code, because it’s a code generation tool.  In fact, getting your programmers to use it could guarantee that they adhere to a Model-View-Controller pattern precisely because they are prevented from writing too much view code beyond keeping their views vapid and vain; IB helps ensure that.

Have you ever sat staring at some code wondering why it’s not working, only to realize you didn’t connect the outlet or action? I hate that.

I don’t know what to say here.  Programmer error?  Rookie mistake?  I’ve been there too at some point.  It’s just a learning curve.  Don’t you hate it when an app crashes and you don’t know how to debug it?  I hate that too.  😉  It should just work like I imagined it.  I will concede that there have been times where I have forgotten to set the delegate, but now I know that this is a source of error once I notice the methods not being called.  I guess one can chalk it up to experience.

Working With Others

Have you ever had a merge conflict in a NIB. It’s the worst…. if it gets automatically merged wrong, you might not notice until runtime. With code, you can read the diff and understand what’s happening.

This is where I definitely concede with you, but this is in my experience not a big deal.  How many developers does it really take to position objects on a screen?  I’ve never been on a project where a developer has said “hey dude, are you done with the NIB file yet?”  (Storyboards not included.)

It’s Part of Xcode

Xcode is not the most stable piece of software in the world. The text editing part works pretty well. Every time I get a crash while editing a NIB, I grumble to myself and wish it was code even more.  The less I have to use Xcode for more than anything except a text editor with completion and a compiler, the happier I am.

Two things; it sounds like you just don’t WANT to like Interface Builder, and two, you’re not one of those VIM guys, are you? 🙂  Anyway, if you don’t like Xcode, you might try AppCode if you’re not using it already.

Location, Location, Location

Layout code is not hard. Trying to work with auto-layout in Interface Builder is maddening … it’s so simple to just override layoutSubviews and do your thing.

True, and true.  Let’s not forget that time is of the essence, so spending time writing lines of code that can otherwise be set with a mouse-click is a task for people working jobs with big budgets.  For the rest of us, anything that will speed up the amount we can get done (well!) is appreciated.

You can simply reuse your code instead of create this tight coupling.

I still don’t understand how you think there’s tight coupling going on.  But anyway, with IB I set the rough position and the auto-resize properties, then do the rest in layoutSubviews as well.  Screw Autolayout.  I don’t know anyone using it, or who has a real use-case for it.

Bottom Line

Interface Builder itself is not bad.

Agreed.

It does encourage bad practices…

I completely disagree, and still haven’t found where you’ve made your argument for this, sorry!

…prevents reusability (making working with others more difficult)…

How?  I just don’t see your argument here.  It gets compiled into code.  A chunk of code with an interface (outlets and actions).

…and slows your workflow.

If this were true, why would it exist?

Personally, I avoid using Interface Builder (including storyboards) as much as possible. All of the projects I’ve worked on since 2009 haven’t had NIBs unless it was out of my control.

Storyboards are a slightly different topic that I’ll just leave alone.  I don’t use them either because I actually want to write controller code, and I think Storyboards take too much of that away, but feel free someone on the interwebs to dispute that.

I think you should save yourself some time, learn a few things, and start moving to code. We are programmers after all.

We are creative people who solve problems, we programmers.  If you were a carpenter, you could saw everything by hand and talk about the purity of your craft, or you could get yourself a fancy woodshop and produce products at a faster speed.  So, your job as a programmer is to build something, and build it well in the quickest amount of time possible.  If you think this is best accomplished without Interface Builder, then that’s your right.  But ultimately all I can say about the “I can’t see what’s happening” and “it slows my workflow” arguments is that you just need to gain some experience with it.  I think it’s a fantastic tool that helps one get an overview of what it’s going to look like at runtime, and saves one having to write a lot of boring code.  You can even drag elements onto your .h/.m files and it will automatically create the outlets for you.  So much LESS typing, allowing you to focus on interesting parts of your application.

If you really are against Interface Builder, then I suggest having a look at DCIntrospect, a very very handy tool that allows you to tweak your view hierarchy (especially frame positioning so you can nudge a view to the left, right, etc until it’s *just right*) at runtime, so at least you don’t have to nudge a frame’s value, compile, run, check, repeat until correct.