Create a gist now

Instantly share code, notes, and snippets.

Embed
NSHipster Call for Tips & Tricks!

Howdy howdy, NSHipsters!

If you alloc init an NSCalendar, you'll notice that New Year's Eve falls on a Monday this year, a.k.a. "the day NSHipster is published every week". What fun!

So in celebration of the upcoming year++, I thought it'd be fun to compile a list of some of your favorite tips and tricks of the trade. Submit your favorite piece of Objective-C trivia, framework arcana, hidden Xcode feature, or anything else you think is cool, and you could have it featured in the year-end blowout article. Just comment on this gist below!

Here are a few examples of the kind of things I'd like to see:

Again, just comment on this Gist below with your submission.

Can't wait to see what y'all come up with!

@jaykz52

This comment has been minimized.

Show comment
Hide comment
@jaykz52

jaykz52 Nov 26, 2012

Not all that esoteric, but using the ObjC runtime to "mixin" new properties on existing classes via associative references can be fun:

// header
@interface NSObject (PornName)

@property (nonatomic, strong) NSString *pornName;

@end

// implementation
#import <objc/runtime.h>

static char const * const PornNameKey = "PornNameKey";

@implementation NSObject (PornName)

@dynamic pornName;

- (NSString *)pornName {
    return objc_getAssociatedObject(self, PornNameKey);
}

- (void)setPornName:(NSString *)pornName {
    objc_setAssociatedObject(self, PornNameKey, pornName, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

@end

jaykz52 commented Nov 26, 2012

Not all that esoteric, but using the ObjC runtime to "mixin" new properties on existing classes via associative references can be fun:

// header
@interface NSObject (PornName)

@property (nonatomic, strong) NSString *pornName;

@end

// implementation
#import <objc/runtime.h>

static char const * const PornNameKey = "PornNameKey";

@implementation NSObject (PornName)

@dynamic pornName;

- (NSString *)pornName {
    return objc_getAssociatedObject(self, PornNameKey);
}

- (void)setPornName:(NSString *)pornName {
    objc_setAssociatedObject(self, PornNameKey, pornName, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

@end
@mayoff

This comment has been minimized.

Show comment
Hide comment
@mayoff

mayoff Nov 26, 2012

Put this in your .lldbinit:

command regex rd 's/^[[:space:]]*$/po [[UIApp keyWindow] recursiveDescription]/' 's/^(.+)$/po [%1 recursiveDescription]/'

Now you can just type rd at the (lldb) prompt to get a dump of your entire view hierarchy. Or you can type rd self.view to get a recursive dump of self.view.

mayoff commented Nov 26, 2012

Put this in your .lldbinit:

command regex rd 's/^[[:space:]]*$/po [[UIApp keyWindow] recursiveDescription]/' 's/^(.+)$/po [%1 recursiveDescription]/'

Now you can just type rd at the (lldb) prompt to get a dump of your entire view hierarchy. Or you can type rd self.view to get a recursive dump of self.view.

@jinthagerman

This comment has been minimized.

Show comment
Hide comment
@shpakovski

This comment has been minimized.

Show comment
Hide comment
@shpakovski

shpakovski Nov 26, 2012

Avoid using +[load] class methods, especially for preloading resources from disk. All of these methods will be called before the applicationDidFinishLaunching: and may greatly increase the launch time bow-wow! Really simple tip, but this problem pops up even in the best open-source frameworks.

Avoid using +[load] class methods, especially for preloading resources from disk. All of these methods will be called before the applicationDidFinishLaunching: and may greatly increase the launch time bow-wow! Really simple tip, but this problem pops up even in the best open-source frameworks.

@ryanmaxwell

This comment has been minimized.

Show comment
Hide comment
@ryanmaxwell

ryanmaxwell Nov 27, 2012

How about clearing up the purpose of all the different pre-processor types? I am still unclear as to why we have nil/Nil/NULL, YES/TRUE/true etc, and generally just use them based on the conventions I see in other code.

How about clearing up the purpose of all the different pre-processor types? I am still unclear as to why we have nil/Nil/NULL, YES/TRUE/true etc, and generally just use them based on the conventions I see in other code.

@mayoff

This comment has been minimized.

Show comment
Hide comment
@mayoff

mayoff Nov 27, 2012

In theory, nil is the null pointer with type id and Nil is the null pointer with type Class. In practice, both are defined to plain old null (with no special type) in <objc/objc.h>.

mayoff commented Nov 27, 2012

In theory, nil is the null pointer with type id and Nil is the null pointer with type Class. In practice, both are defined to plain old null (with no special type) in <objc/objc.h>.

@mayoff

This comment has been minimized.

Show comment
Hide comment
@mayoff

mayoff Nov 27, 2012

Want to print the elements of a CGPathRef from the debugger?

p (void)CGPathPrint(pathRef, 0)

mayoff commented Nov 27, 2012

Want to print the elements of a CGPathRef from the debugger?

p (void)CGPathPrint(pathRef, 0)
@alextud

This comment has been minimized.

Show comment
Hide comment
@alextud

alextud Nov 27, 2012

A much easier way to measure a piece of code:

NS_INLINE void MVComputeTimeWithNameAndBlock(const char *caller, void (^block)()) {
    CFTimeInterval startTimeInterval = CACurrentMediaTime();
    block();
    CFTimeInterval nowTimeInterval = CACurrentMediaTime();
    NSLog(@"%s - Time Running is: %f", caller, nowTimeInterval - startTimeInterval);
}

#define MVComputeTime(...) MVComputeTimeWithNameAndBlock(__PRETTY_FUNCTION__, (__VA_ARGS__))

alextud commented Nov 27, 2012

A much easier way to measure a piece of code:

NS_INLINE void MVComputeTimeWithNameAndBlock(const char *caller, void (^block)()) {
    CFTimeInterval startTimeInterval = CACurrentMediaTime();
    block();
    CFTimeInterval nowTimeInterval = CACurrentMediaTime();
    NSLog(@"%s - Time Running is: %f", caller, nowTimeInterval - startTimeInterval);
}

#define MVComputeTime(...) MVComputeTimeWithNameAndBlock(__PRETTY_FUNCTION__, (__VA_ARGS__))
@alextud

This comment has been minimized.

Show comment
Hide comment
@alextud

alextud Nov 27, 2012

An example:

MVComputeTime(^{
    for (NSEntityDescription *entity in [[[NSPersistentStoreCoordinator MR_defaultStoreCoordinator] managedObjectModel] entities])     {
        NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:[entity name]];
        NSLog(@"%@ - objects count - %d",  [entity name], [[NSManagedObjectContext MR_defaultContext] countForFetchRequest:fetchRequest error:nil]);
    }
});

alextud commented Nov 27, 2012

An example:

MVComputeTime(^{
    for (NSEntityDescription *entity in [[[NSPersistentStoreCoordinator MR_defaultStoreCoordinator] managedObjectModel] entities])     {
        NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:[entity name]];
        NSLog(@"%@ - objects count - %d",  [entity name], [[NSManagedObjectContext MR_defaultContext] countForFetchRequest:fetchRequest error:nil]);
    }
});
@MaxGabriel

This comment has been minimized.

Show comment
Hide comment
@MaxGabriel

MaxGabriel Nov 27, 2012

Not sure if hipster enough, but using code snippets effectively. I think they're underused for documentation

Not sure if hipster enough, but using code snippets effectively. I think they're underused for documentation

@joelparsons

This comment has been minimized.

Show comment
Hide comment
@joelparsons

joelparsons Nov 29, 2012

- enumerateObjectsWithOptions: usingBlock:

for the various collection objects. The magic about this is the option NSEnumerationConcurrent. It will enumerate different iterations of the loop concurrently. Useful in certain situations, dangerous in others. Think that makes it cool enough for NSHipsters.

- enumerateObjectsWithOptions: usingBlock:

for the various collection objects. The magic about this is the option NSEnumerationConcurrent. It will enumerate different iterations of the loop concurrently. Useful in certain situations, dangerous in others. Think that makes it cool enough for NSHipsters.

@mattt

This comment has been minimized.

Show comment
Hide comment
@mattt

mattt Nov 29, 2012

These are all awesome, guys. Thanks for the great tips! Keep it up!

Owner

mattt commented Nov 29, 2012

These are all awesome, guys. Thanks for the great tips! Keep it up!

@0xced

This comment has been minimized.

Show comment
Hide comment
@0xced

0xced Dec 3, 2012

See function static id _target(id autoContentAccessingProxy) for accessing a private ivar. You should obviously never ship your app with such code but it may be helpful for debugging.

0xced commented Dec 3, 2012

See function static id _target(id autoContentAccessingProxy) for accessing a private ivar. You should obviously never ship your app with such code but it may be helpful for debugging.

@0xced

This comment has been minimized.

Show comment
Hide comment
@0xced

0xced Dec 3, 2012

extern NSString *const and weak linking does’t work the way you think it works, from https://gist.github.com/3725528:

#import <Social/Social.h>

/* Compiled with iOS 6 SDK
 * Social.framework weak linked (Optional)
 * Run on iOS 5.1 (simulator and device)
 * Output is:
 * 0x0
 * About to crash
 * +++ EXC_BAD_ACCESS +++
 */

int main(int argc, char *argv[])
{
    @autoreleasepool
    {
        NSLog(@"%p", &SLServiceTypeFacebook);
        if (&SLServiceTypeFacebook)
        {
            NSLog(@"About to crash");
            NSString *serviceType = SLServiceTypeFacebook; // crashes here with EXC_BAD_ACCESS (code=2, address=0x0)
            NSLog(@"Not reached %@", serviceType);
        }
    }
    return 0;
}

0xced commented Dec 3, 2012

extern NSString *const and weak linking does’t work the way you think it works, from https://gist.github.com/3725528:

#import <Social/Social.h>

/* Compiled with iOS 6 SDK
 * Social.framework weak linked (Optional)
 * Run on iOS 5.1 (simulator and device)
 * Output is:
 * 0x0
 * About to crash
 * +++ EXC_BAD_ACCESS +++
 */

int main(int argc, char *argv[])
{
    @autoreleasepool
    {
        NSLog(@"%p", &SLServiceTypeFacebook);
        if (&SLServiceTypeFacebook)
        {
            NSLog(@"About to crash");
            NSString *serviceType = SLServiceTypeFacebook; // crashes here with EXC_BAD_ACCESS (code=2, address=0x0)
            NSLog(@"Not reached %@", serviceType);
        }
    }
    return 0;
}
@0xced

This comment has been minimized.

Show comment
Hide comment
@0xced

This comment has been minimized.

Show comment
Hide comment
@0xced

0xced Dec 3, 2012

Using NSPropertyListSerialization to implement base64 encoding and decoding in less than 50 lines with support for iOS 2.0 and OS X 10.5.

0xced commented Dec 3, 2012

Using NSPropertyListSerialization to implement base64 encoding and decoding in less than 50 lines with support for iOS 2.0 and OS X 10.5.

@SlaunchaMan

This comment has been minimized.

Show comment
Hide comment
@SlaunchaMan

SlaunchaMan Dec 3, 2012

How about associated objects? You know it’s going down when you see this at the top of one of my files:

#import <objc/runtime.h>

static const void *kMyKey = &kMyKey;

How about associated objects? You know it’s going down when you see this at the top of one of my files:

#import <objc/runtime.h>

static const void *kMyKey = &kMyKey;
@shpakovski

This comment has been minimized.

Show comment
Hide comment
@shpakovski

shpakovski Dec 3, 2012

In iOS 6 you can animate a constant property in NSLayoutConstraint:

viewConstraint.constant = ConstantValueFrom;
[view layoutIfNeeded];

viewConstraint.constant = ConstantValueTo;
[view setNeedsUpdateConstraints];

[UIView animateWithDuration:ConstantAnimationDuration animations:^{
     [view layoutIfNeeded];
}];

In iOS 6 you can animate a constant property in NSLayoutConstraint:

viewConstraint.constant = ConstantValueFrom;
[view layoutIfNeeded];

viewConstraint.constant = ConstantValueTo;
[view setNeedsUpdateConstraints];

[UIView animateWithDuration:ConstantAnimationDuration animations:^{
     [view layoutIfNeeded];
}];
@0xced

This comment has been minimized.

Show comment
Hide comment
@0xced

0xced Dec 3, 2012

Printing NSCache usage information (tested on iOS only):

extern void cache_print(void *cache);

- (void) printCache:(NSCache *)cache
{
    cache_print(*((void **)(__bridge void *)cache + 3));
}

Use for debugging only!

0xced commented Dec 3, 2012

Printing NSCache usage information (tested on iOS only):

extern void cache_print(void *cache);

- (void) printCache:(NSCache *)cache
{
    cache_print(*((void **)(__bridge void *)cache + 3));
}

Use for debugging only!

@mattt

This comment has been minimized.

Show comment
Hide comment
@mattt

mattt Dec 31, 2012

Thanks again, everyone, for your great submissions! These have now been compiled into this special New Year's Eve Edition of NSHipster. Cheers!

Owner

mattt commented Dec 31, 2012

Thanks again, everyone, for your great submissions! These have now been compiled into this special New Year's Eve Edition of NSHipster. Cheers!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment