Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
NSHipster New Year's 2015

Season's Greetings, NSHipsters!

As the year winds down, and we take a moment to reflect on our experiences over the past months, one thing is clear: 2014 has been an incredible year professionally for Apple developers. So much has happened in such a short timespan, and yet it's hard to remember our relationship to Objective-C before Swift, or what APIs could have captivated our imagination as much as iOS 8 or WatchKit.

It's an NSHipster tradition to ask you, dear readers, to send in your favorite tips and tricks from the past year for publication over the New Year's holiday. This year, with the deluge of new developments—both from Cupertino and the community at large—there should be no shortage of interesting tidbits to share.

Submit your favorite piece of Swift or 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!

If you're wondering about what to post, look to past year's write-ups for inspiration (2014, 2013).

I can't wait to see what you all send in!

My small contribution, just to start off the list. It's nothing revelatory, but I thought it's worth sharing: in Xcode's editor pressing ⌃6 brings up Show Document Items window, from which one can quickly jump to definitions/declarations. Cool thing about it: to quickly find items, we can start typing them right after bringing up this window (just like in quick open dialog - ⌘⇧O).

Asserts can offer a lot of value in detecting when an expectation that MUST hold in your code ends up not holding. To simplify asserting a little more, you can wrap the NSCAssert macro to provide some simplicity. 1) by wrapping NSCAssert, the assert will work in C code or Objective-C code (since NSAssert only works in Objective-C code), 2) using the preprocessor we can put the expression we are evaluating into the message of the assert automatically, eliminating the need to provide a string to the NSCAssert macro, and 3) we can stop the debugger at the point of the assertion so that the call execution state can be preserved without having to set a breakpoint, helping to debug.

#if DEBUG
NS_INLINE __MyAssert(BOOL expressionValue)
{
    // AmIBeingDebugged from https://developer.apple.com/library/mac/qa/qa1361/_index.html
    if (! expressionValue && AmIBeingDebugged()) {
            kill(getpid(), SIGSTOP);
    }
}
#define MyAssert(expression) \
do { \
    BOOL value = (expression); \
    __MyAssert(value);
    NSCAssert(value, @"assertion failed: (" #expression ")"); \
} while (0)
#else
#define MyAssert(expression) ((void)0)
#endif

We can use it like so:

- (void)foo
{
    MyAssert(self.count > 0);
}

and if you hit continue in the debugger (or don't have the debugger attached) you'll get:

TIME_STAMP_1 MyApp[ID] *** Assertion failure in PRETTY_FUNCTION & FILE_NAME
TIME_STAMP_2 MyApp[ID] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'assertion failed: (self.count > 0)'
*** First throw call stack:
(
    +++ stack trace ++
)
libc++abi.dylib: terminating with uncaught exception of type NSException

Now searching for MyAssert(self.count > 0) or even just self.count > 0 will take you right to the place in code that you need to find. Of course, if you are debugging, when the debugger is stopped you'll have a preserved execution state and one of the suspended threads will have the assert being triggered.

I also like to keep asserts out of production and the macro is set up to no-op the asserts outside of debug builds. This can be changed to fit your asserting needs of course.

One powerful class in Foundation is the NSUserDefaults. This class makes persisting small user settings across runs a breeze. Sometimes a setting can be updated and we have other areas of the app that need to observe the change. Thankfully, Apple had the foresight to make NSUserDefaults KVO compliant by key. By using KVO on NSUserDefaults, any part of your app that cares about that setting can be immediately informed of the change and update accordingly.

[[NSUserDefaults standardDefaults] addObserver:self forKeyPath:@"MyApp.UserFullName" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:NULL];

Whenever the setting in the user defaults for @"user.fullname" changes (with a call like [[NSUserDefaults standardDefaults] setObject:@"Mattt Thompson" forKey:@"MyApp.UserFullName"]), any observers can fall in line and observe the change.

Take this knowledge a step further and it would be simple to create some kind of wrapper to keep the KVO adding and removing balanced for safety as well as providing an easier to use block or target/action instead of having to litter your classes with - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context

The true power that this shows is when you trying to pair user defaults with some global setting and notifications to indicate change. 1) the global variable goes away eliminating the synchronization between it and the user default value. 2) The manually triggered notification is no longer necessary so the pairing between setting the value and posting the notification melts to just updating the value. 3) If the value (stored in the user defaults) is encapsulated by a class, there is no longer a worry of the user default being modified from outside the encapsulation since the class can just observe the change. Win, win, win.

I don't know how useful it is, but you can make every class in swift a singleton by extending it.

extension SomeClass {
    class var SharedInstance: SomeClass  {
        struct Static {
            static let instance: SomeClass = SomeClass ()
        }
        return Static.instance
    }
}

0xced commented Nov 26, 2014

Quick way to check all the pods used by a (closed source) app:

class-dump -C Pods_ /Applications/Squire.app | grep -o "Pods_\w+"

0xced commented Nov 26, 2014

I discovered the CREATE_INFOPLIST_SECTION_IN_BINARY Xcode setting recently for command-line apps. It’s much easier to use than the -sectcreate __TEXT __info_plist linker flag and it embeds the processed Info.plist file into the binary.

It’s also a lesson on filing radars. This feature request was filed as rdar://4722772 in 2006 and was addressed about 7 years later.

0xced commented Nov 26, 2014

Make hackers’ life tougher with this trick from Sam Marshall:

Want to stop dylib hooking into your app? Add this one line to your “Other Linker Flags” :P
-Wl,-sectcreate,__RESTRICT,__restrict,/dev/null

0xced commented Nov 26, 2014

If you gave up on reading the official iOS 7.1 to iOS 8.0 and the OS X v10.9 to OS X v10.10 API differences because of the noise mostly generated by transforming getter/setters into properties and id into instancetype, I created curated versions for iOS and OS X.

Also interesting is the source code that generated these curated documents. Less than 200 lines of code thanks to the powerful NSXMLDocument/XPath APIs.

0xced commented Nov 26, 2014

If you are installing Xcode from the dmg, I highly recommend this technique by Joar Wingfors in order to avoid to accidentally modifying SDK headers.

Preserve ownership, permissions and hard links installing Xcode from a dmg:
sudo ditto /Volumes/Xcode/Xcode.app /<destination>/Xcode.app

I personally add the -V flag to ditto for verbose logging.

0xced commented Nov 26, 2014

For reverse engineering purpose, it’s always useful to look at instance variables of objects. It’s usually pretty easy to do so with valueForKey: since very few classes override the +accessInstanceVariablesDirectly
method to disable ivar acces through Key-Value Coding.

There’s one case where it doesn’t work though: when the ivar has a void * type. Here is an excerpt of the MediaPlayer framework class-dump on iOS 6.1:

@interface MPMoviePlayerController : NSObject <MPMediaPlayback>
{
    void *_internal;    // 4 = 0x4
    BOOL _readyForDisplay;  // 8 = 0x8
}

Since id internal = [moviePlayerController valueForKey:@"internal"] doesn’t work, here is the hardcore way to access the internal ivar:

id internal = *((const id*)(void*)((uintptr_t)moviePlayerController + sizeof(Class)));

Don’t ship this code, its’s very fragile because the ivar layout may change. Use this for reverse engineering only!

0xced commented Nov 26, 2014

Friendly reminder that if you are using -[NSDateFormatter setDateFormat:] without +[NSDateFormatter dateFormatFromTemplate:options:locale:], you’re probably doing it wrong.

0xced commented Nov 26, 2014

Recently, Matthias Tretter asked on Twitter:

Does anyone know the default animation duration and springs for modal viewController presentation on iOS 8?

Here is how to answer this question in 3 minutes:

  • Search for duration in a class-dump of UIKit

  • Find the +[UITransitionView defaultDurationForTransition:] method

  • Set a breakpoint for this method:

    (lldb) br set -n "+[UITransitionView defaultDurationForTransition:]"
    
  • Present a modal view controller, you will hit the breakpoint, type finish to execute the method

    (lldb) finish
    
  • At that point the defaultDurationForTransition: has executed and you can read the result, it’s in the xmm0 register.

    (lldb) register read xmm0 --format float64
        xmm0 = {0.4 0}
    

Answer: the default duration is 0.4s.

0xced commented Nov 26, 2014

Quick tip from @bensge:

Wow +[UIViewController _printHierarchy] is like -[UIView recursiveDescription] but for view controllers! #Development

0xced commented Nov 26, 2014

DIY weak associated objects, adapted from my Stack Overflow answer:

Unfortunately, the associated objects OBJC_ASSOCIATION_ASSIGN policy does not do zeroing weak reference. Fortunately, it’s quite easy to implement yourself. You just need a simple class to wrap an object with a weak reference:

@interface WeakObjectContainter : NSObject
@property (nonatomic, readonly, weak) id object;
@end

@implementation WeakObjectContainter
- (instancetype) initWithObject:(id)object
{
    if (!(self = [super init]))
        return nil;

    _object = object;

    return self;
}
@end

Then you must associate the WeakObjectContainter as OBJC_ASSOCIATION_RETAIN(_NONATOMIC):

objc_setAssociatedObject(self, &MyKey, [[WeakObjectContainter alloc] initWithObject:object], OBJC_ASSOCIATION_RETAIN_NONATOMIC);

and use the object property to access it in order to get a zeroing weak reference:

id object = [objc_getAssociatedObject(self, &MyKey) object];

Here is a convenient way to access child controllers inserted into Storyboard container views:

// 1. A property has the same name as a segue identifier in XIB
@property (nonatomic) ChildViewController1 *childController1;
@property (nonatomic) ChildViewController2 *childController2;

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    [super prepareForSegue:segue sender:sender];

    // 2. All known destination controllers assigned to properties
    if ([self respondsToSelector:NSSelectorFromString(segue.identifier)])
        [self setValue:segue.destinationViewController forKey:segue.identifier];
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    // 3. Controllers already available bc viewDidLoad is called after prepareForSegue
    self.childController1.view.backgroundColor = [UIColor redColor];
    self.childController2.view.backgroundColor = [UIColor blueColor];
}

You can Edit Breakpoint in Xcode by Option-Command-Click on the blue indicator.

orta commented Nov 28, 2014

AppCode.

CodaFi commented Nov 28, 2014

Member functions on Swift classes and structures always have the following type when used statically:

Object -> (Args) -> Thing

For example, you can call reverse() on an array in two ways

[1, 2, 3, 4].reverse()
Array.reverse([1, 2, 3, 4])()

zobkiw commented Nov 28, 2014

I'm a fan of the Objective-C Runtime functions objc_getAssociatedObject and objc_setAssociatedObject. These allow the ability to "associate" an object with another object. This association can survive the life of the source object. Imagine tacking "data" onto a button that the button's IBAction can then access when tapped. Lots of possibilities with these functions.

Cool instruments tricks to counter memory leaks - https://medium.com/hacking-ios/a-day-with-instruments-tool-414ad50234f1
Also CGParallaxCollectionView written very early when Swift was annouced - https://github.com/kNeerajPro/CGParallaxCollectionView

bitops commented Dec 1, 2014

Shameless plug for some Array extensions I wrote to mimic some of the popular methods from Ruby's Enumerable module. Attributions, where applicable, are in the source. https://github.com/bitops/swift-collections/blob/master/SwiftCollections.swift

defagos commented Dec 1, 2014

Instead of if-testing a block against nil before calling it:

if (block) {
    result = block(param1, param2);
}
else {
    result = defaultValue;
}

if love using the one-liner:

result = block ? block(param1, param2) : defaultValue;

to declutter my code. For blocks returning void, simply use nil as default value:

voidBlock ? voidBlock(param1, param2) : nil;

defagos commented Dec 1, 2014

Given the fact that literals are most of the time associated with numbers and collections, I often forget that they work for UTF8-encoded NULL-terminated C-strings as well, especially when I write code using the runtime:

NSString *propertyAttributesString = @(property_getAttributes(class_getProperty([NSObject class], "description")));         // T@"NSString",R,C

It is namely quite amusing that:

[@("someString") isEqualToString:@"someString"] == YES

is something I so easily forget, especially since this boxing syntax is totally natural.

cmyr commented Dec 1, 2014

Optionals should be avoided. Implicitly unwrapped optionals should be strongly avoided. Want to declare a var but don't necessarily have an initial value at init time? Use the lazy keyword, and just don't call the getter before you have your real value.

lazy var someModelStructure = ExpensiveClass()

if you call set on this var without having ever called the getter, the lazy expression is never evaluated. Great for references to views that you don't necessarily want to init until viewDidLoad, for instance.

incanus commented Dec 4, 2014

Now that 10.10 is allowing easy screencasts of iOS devices (which itself is a neat tip), I find myself again using a framework I made some time back for showing touches on screen: Fingertips. Great for presentations, too.

You can optional chain calling a closure just like you can accessing a subscript

func foo(completion: ((String) -> Void)?) {
    completion?("Heyo!!") ?? println("Oyeh!!")
}

foo { println($0) }     // prints "Heyo"
foo(nil)                // prints "Oyeh"

0xced commented Dec 9, 2014

Sometimes, you need to know which language your app is running in. Often, people will use +[NSLocale preferredLanguages]. Unfortunately this tells nothing about the language the app is actually displaying. It will just give you the ordered list as found in Settings → General → Language & Region → Preferred Language Order on iOS or System Preferences → Language & Region → Preferred Languages on OS X.

Imagine that the preferred language order is {English, French} but your app is German only. Calling [[NSLocale preferredLanguages] firstObject] will give you English when you want German.

The proper way to get the actual language used by the app is to use [[NSBundle mainBundle] preferredLocalizations].

From the documentation:

An array of NSString objects containing language IDs for localizations in the bundle. The strings are ordered according to the user's language preferences and available localizations.

From a comment in NSBundle.h:

a subset of this bundle's localizations, re-ordered into the preferred order for this process's current execution environment; the main bundle's preferred localizations indicate the language (of text) the user is most likely seeing in the UI

You may also need to use +[NSLocale canonicalLanguageIdentifierFromString:] in order to ensure a canonical language identifier.

Functional Programming vs OOP vs Imperative Programming

dodikk commented Dec 9, 2014

@samirGuerdah vs "Playground Driven Development" )))

fpillet commented Dec 9, 2014

When you have objects in a NSArray, you can extract another NSArray with the value returned from a selector applied to each object using -valueForKey. This call will turn the string into a @selector if it doesn't find a property with the same name, and call the selector:

NSArray *array = <some array of NSObject> ;
NSArray *descriptions = [array valueForKey:@"description"];

The cool thing is that this works with any selector you define on your objects.

This is part of the key-value coding conventions. Relevant documentation for NSArray is here

hborders commented Dec 9, 2014

If you're repeatedly debugging the same problem over and over, you can run your app without rebuilding by using <ctrl>+<cmd>+r.

Swift Playgrounds all share the same Shared Playground Data folder that's symlinked to /Users/HOME/Documents/Shared Playground Data.

If you like using lots of Playgrounds, you'll want to organize the data that each Playground is using into subfolders of that shared folder, but then you've got to let the Playground know where to look. Here's a helper function that I use that makes that easy:

func pathToFileInSharedSubfolder(file: String) -> String {
    return XCPSharedDataDirectoryPath + "/" + NSProcessInfo.processInfo().processName + "/" + file
}

That processName property in NSProcessInfo contains the name of the Playground file, so as long as you have already created a sub-folder in the Shared Playground Data folder with the same name you can access those files pretty easily, like reading local JSON:

var jsonReadError:NSError?
let jsonData = NSFileManager.defaultManager().contentsAtPath(pathToFileInSharedSubfolder("data.json"))!
let jsonArray = NSJSONSerialization.JSONObjectWithData(jsonData, options: nil, error: &jsonReadError) as [AnyObject]

or pulling out a local image:

let imageView = UIImageView()
imageView.image = UIImage(contentsOfFile: pathToFileInSharedSubfolder("image.png"))

Fl0p commented Dec 10, 2014

Cocoapods
@orta 😉

palewar commented Dec 16, 2014

Playground as Documentation.

And also Firefox coming to iOS and looks to be mostly done in Swift. It's still early days and a great opportunity for community to get involved with the development. Contributing guidelines are non existent and so are code comments, making it difficult to get involved. If somebody can do some digging and come up with some simple guidelines and code comments for existing code, it will be great for everybody.

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