Slide 1

Slide 1 text

Understanding Objective- C Inside and Out CocoaConf Columbus, September 27th, 2013 Jeff Kelley @SlaunchaMan Saturday, September 28, 13

Slide 2

Slide 2 text

Who? Saturday, September 28, 13

Slide 3

Slide 3 text

Objective-C’s Beginning • Developed by Brad Cox and Tom Love in the early 1980s • Originally OOPC, or Object Oriented Pre- Compiler • Was originally a C precompiler! • Acquired by NeXT in 1995 • Apple now owns Objective-C rights Saturday, September 28, 13

Slide 4

Slide 4 text

Why Objective-C? • Compatibility with existing C code • Originally developed to work alongside telecom C code • Brings in the object-oriented nature of Smalltalk Saturday, September 28, 13

Slide 5

Slide 5 text

Smalltalk | bigNumber | bigNumber := 42 factorial 'helloWorld' indexOf: $o startingAt: 6 Saturday, September 28, 13

Slide 6

Slide 6 text

Early Objective-C Saturday, September 28, 13

Slide 7

Slide 7 text

Early Objective-C • Tim Berners-Lee wrote the first web browser, WorldWideWeb, on a NeXT Cube in Objective-C in 1989/1990 • Let’s look at some source code! Saturday, September 28, 13

Slide 8

Slide 8 text

Early Objective-C - readPrintInfo /* * Sets the margin fields from the Application-wide PrintInfo. */ { id pi; float conversion, dummy; NXCoord left, right, top, bottom; [super readPrintInfo]; pi = [NXApp printInfo]; [self convertOldFactor:&conversion newFactor:&dummy]; [pi getMarginLeft:&left right:&right top:&top bottom:&bottom]; [leftMargin setFloatValue:left * conversion]; [rightMargin setFloatValue:right * conversion]; [topMargin setFloatValue:top * conversion]; [bottomMargin setFloatValue:bottom * conversion]; return self; } Saturday, September 28, 13

Slide 9

Slide 9 text

Why do we still use it? • C is powerful • C is fast • Apple owns it • See recently-developed features: properties, ARC, blocks, literals • What else would we use? Saturday, September 28, 13

Slide 10

Slide 10 text

Cargo Cults Saturday, September 28, 13

Slide 11

Slide 11 text

Today’s Agenda • Why do I get all these weird linker errors? • objc_msgSend() keeps crashing! • Why can’t I add an instance variable in a category? • How can Apple still be using Objective-C? Saturday, September 28, 13

Slide 12

Slide 12 text

Weird Linker Errors • Can freeze a new Objective-C programmer in his or her tracks • Simple, but cryptic error messages • Cross-library troubles Saturday, September 28, 13

Slide 13

Slide 13 text

Demo Saturday, September 28, 13

Slide 14

Slide 14 text

What happens when you send a message? •objc_msgSend() • Hey, I see that in my crash logs all the time! They should work on that! • Found in • If you want to pass an argument, you need to cast it • Useful for calling private APIs Saturday, September 28, 13

Slide 15

Slide 15 text

Calling Private API Let’s call -recursiveDescription on a view. NSString *recursiveDescription = objc_msgSend(self.window, @selector(recursiveDescription)); Saturday, September 28, 13

Slide 16

Slide 16 text

Calling Private API • OK, that was easy. But what if something takes an argument? Or returns a C primitive? • You get to cast objc_msgSend() to the appropriate function type Saturday, September 28, 13

Slide 17

Slide 17 text

Casting objc_msgSend() NSArray *myArray = @[ @1, @2, @3 ]; NSUInteger (*unsignedIntegerMessage)(id obj, SEL message) = (NSUInteger (*)(id, SEL))objc_msgSend; NSUInteger count = unsignedIntegerMessage(myArray, @selector(count)); Saturday, September 28, 13

Slide 18

Slide 18 text

Casting objc_msgSend() • Hey, that looks like block syntax! • C function pointer syntax was here first • Don’t do this with other functions—this one is expecting it • Lots of hand-written assembly code per platform in objc_msgSend() Saturday, September 28, 13

Slide 19

Slide 19 text

objc_msgSend() Family • id objc_msgSend(id self, SEL op, ...); • id objc_msgSendSuper(id self, SEL op, ...); • long double objc_msgSend_fpret(id self, SEL op, ...); • void objc_msgSend_stret(id obj, SEL op, ...); Saturday, September 28, 13

Slide 20

Slide 20 text

objc_msgSend() Family • 64-bit iOS: •objc_msgSend(id self, SEL op, ...); Saturday, September 28, 13

Slide 21

Slide 21 text

So what does objc_msgSend() do? • Every Objective-C method compiles to a C implementation, or IMP • These are looked up by name (the selector) and cached for performance • “Objective-C is slow” • objc_msgSend() finds the IMP and calls it • So if the stack explodes, you see it Saturday, September 28, 13

Slide 22

Slide 22 text

Why is this useful? • Implement two Objective-C methods with one underlying C function • Override - (IMP)methodForSelector: (SEL)aSelector; • Or graft existing C functionality to Objective-C • Method Swizzling Saturday, September 28, 13

Slide 23

Slide 23 text

Method Swizzling • If you need to modify behavior of a class you don’t own (like UIView), you can replace a method implementation with one of your own • A combination of class_addMethod() and method_setImplementation() Saturday, September 28, 13

Slide 24

Slide 24 text

Demo Saturday, September 28, 13

Slide 25

Slide 25 text

Objects and Instance Variables • Why can’t I add an instance variable in a category? • Where am I supposed to add instance variables, anyway? Saturday, September 28, 13

Slide 26

Slide 26 text

What is an Object? • From : typedef struct objc_object { Class isa; } *id; • It’s just a C struct! • Well, not recently. • You can do object->instanceVariable Saturday, September 28, 13

Slide 27

Slide 27 text

Memory Layout • Objective-C objects are laid out like structs • First member is always the isa pointer • Points to class • So to know where an instance variable is, we need to know the entire hierarchy • Therefore, we can’t add anything in a category Saturday, September 28, 13

Slide 28

Slide 28 text

Why do we always use pointers? • With a complex object hierarchy, hundreds of instance variables might be on one class • Can’t make all these objects on the stack • Would use too much memory • Would die with the stack • All objects are created on the heap, we use pointers to find them Saturday, September 28, 13

Slide 29

Slide 29 text

Reference Counting • How do we know when to free the memory an object is using? • Despite how we talk about it, the system is not as complicated as you might think • Objects don’t really know about each other, they just store pointers to them • Retain/release used based on simple rules Saturday, September 28, 13

Slide 30

Slide 30 text

ARC • ARC is a simple system of rules • Placing an object’s address in a pointer variable? Retain it. • A pointer variable containing an object’s address falls out of scope or is getting a new value? Release it. • The method starts with alloc, new, copy, or create? Autorelease it instead. Saturday, September 28, 13

Slide 31

Slide 31 text

ARC • ARC adds an optimization layer on top of these simple rules to get really fast • objc_retain() faster than [object retain]; Saturday, September 28, 13

Slide 32

Slide 32 text

What if my category needs storage? • Objective-C is really good at looking up values in storage • Honed through the message dispatch system • Associated objects API allows arbitrary storage of object associations • objc_setAssociatedObject() and friends Saturday, September 28, 13

Slide 33

Slide 33 text

Demo Saturday, September 28, 13

Slide 34

Slide 34 text

Places to Add Instance Variables • The public header @interface MyClass : NSObject { id obj; } • Encourages direct instance variable access by others, should be avoided • Use a property instead Saturday, September 28, 13

Slide 35

Slide 35 text

Places to Add Instance Variables • The implementation block @implementation MyClass { id obj; } • Limits access to implementation file • Property access is still safer, but with ARC this is reasonably safe Saturday, September 28, 13

Slide 36

Slide 36 text

Places to Add Instance Variables • The class extension @interface MyClass() { id obj; } • If you’re also adding methods in the class extension, it’s only logical to place these here as well Saturday, September 28, 13

Slide 37

Slide 37 text

Dynamic Classes • No, really, I need to modify the behavior of an object at runtime. • Apple already does this with KVO • So how do they do it? Saturday, September 28, 13

Slide 38

Slide 38 text

KVO in Action • First, the API creates a subclass of your class at runtime: Class mySubclass = objc_allocateClassPair([NSObject class], "MySubclass", 0); Saturday, September 28, 13

Slide 39

Slide 39 text

KVO in Action • Second, the API sets your object to this new class object_setClass(object, mySubclass); • DO NOT set the isa pointer directly •object->isa = mySubclass; Saturday, September 28, 13

Slide 40

Slide 40 text

KVO in Action • Third, the API implements the method(s) it wants to override: - (void)setFoo:(id)foo { NSLog(@"About to set foo!"); [super setFoo:foo]; NSLog(@"Set foo!"); } Saturday, September 28, 13

Slide 41

Slide 41 text

KVO in Action • Finally, the API overrides -class to hide what it’s done • So -isMemberOfClass: still works for the original class Saturday, September 28, 13

Slide 42

Slide 42 text

Why would I need to do this? • Here’s an actual, real-life example of dynamic subclassing: Kiwi mocks • In Kiwi, the BDD test framework, you can stub a method like this: •[viewController stub:@selector(view) andReturn:thisMockView]; Saturday, September 28, 13

Slide 43

Slide 43 text

Why would I need to do this? • In production applications, you won’t need to do this too often • But in testing, it’s invaluable Saturday, September 28, 13

Slide 44

Slide 44 text

So How is Apple Still Using Objective-C? • As KVO illustrates, Objective-C is extremely capable of runtime hackery • As the sole owner, Apple is free to make insane improvements to the language • Tagged Pointers • The isa pointer in 64-bit iOS • Excellent tool development in LLVM/Clang Saturday, September 28, 13

Slide 45

Slide 45 text

Tagged Pointers • A pointer to an object will, due to alignment, have some extra bits • The last bit is always 0… or is it? • Apple sets the last bit to 1 and uses the remaining bits to store integers • Looks and acts just like an NSNumber, but needs no additional storage Saturday, September 28, 13

Slide 46

Slide 46 text

Tagged Pointers • Don’t try to set the isa pointer. Bad things will happen. • Best-case scenario: compiler error. • 64-bit iOS means we get tagged pointers • Performance/memory gains for free! Saturday, September 28, 13

Slide 47

Slide 47 text

64-Bit iOS isa Pointer http://www.sealiesoftware.com/blog/ Saturday, September 28, 13

Slide 48

Slide 48 text

LLVM Saturday, September 28, 13

Slide 49

Slide 49 text

LLVM/Clang Optimizations • Link-Time Optimization • Applies compiler optimizations across source files, leading to huge potential gains • New optimization level -Ofast • Not suitable for scientific applications that need precise floating-point values Saturday, September 28, 13

Slide 50

Slide 50 text

Where is Objective-C Going? • Recent Objective-C developments have made developing faster • Auto-synthesized property accessors • ARC • Packages • Object Literals Saturday, September 28, 13

Slide 51

Slide 51 text

Where is Objective-C Going? • Recent Objective-C developments have reduced the cognitive load of the language • ARC • Packages • Properties Saturday, September 28, 13

Slide 52

Slide 52 text

Where is Objective-C Going? • Future developments will likely continue down these paths • My suggestion: get rid of pointers • “What? Are you crazy?” • The compiler is smart enough to re- insert them where needed Saturday, September 28, 13

Slide 53

Slide 53 text

Q&A Saturday, September 28, 13

Slide 54

Slide 54 text

References • http://en.wikipedia.org/wiki/Objective-C • http://en.wikipedia.org/wiki/Tim_Berners-Lee • http://www.mikeash.com/pyblog/friday-qa-2013-09-27- arm64-and-you.html • http://www.sealiesoftware.com/blog/archive/2013/09/24/ objc_explain_Non-pointer_isa.html • https://twitter.com/marcoarment/status/ 383083874676641792 • http://llvm.org/docs/LinkTimeOptimization.html Saturday, September 28, 13