Discover millions of ebooks, audiobooks, and so much more with a free trial

Only $11.99/month after trial. Cancel anytime.

The Complete Friday Q&A: Volume II
The Complete Friday Q&A: Volume II
The Complete Friday Q&A: Volume II
Ebook2,174 pages8 hours

The Complete Friday Q&A: Volume II

Rating: 0 out of 5 stars

()

Read preview

About this ebook

The Complete Friday Q&A is a collection of articles on advanced topics in macOS and iOS programming. With articles on multithreading, assembly language, debugging, Objective-C, and more, this book is your gateway to becoming fluent in complicated, obscure, and arcane corners of Mac and iOS programming.
LanguageEnglish
PublisherLulu.com
Release dateOct 2, 2017
ISBN9781365953125
The Complete Friday Q&A: Volume II

Related to The Complete Friday Q&A

Related ebooks

Computers For You

View More

Related articles

Reviews for The Complete Friday Q&A

Rating: 0 out of 5 stars
0 ratings

0 ratings0 reviews

What did you think?

Tap to rate

Review must be at least 10 words

    Book preview

    The Complete Friday Q&A - Mike Ash

    Index

    About The Complete Friday Q&A: Volume II

    Friday Q&A is a biweekly series on Mac programming. It can be found online at https://mikeash.com/pyblog/. Volume II is a full archive of all posts from November 2010 to November 2012.

    The author gratefully acknowledges all of the topic and comment contributions to Friday Q&A from its readers.

    The Complete Friday Q&A: Volume II Copyright © 2010-2017 by Michael Ash

    Mike Ash

    mike@mikeash.com

    https://mikeash.com/

    Introduction

    It's been a long time since the release of The Complete Friday Q&A: Volume I, and it's well past time for the next collection in the set. We have a wide variety of great topics for you, from multithreading to disassemblers to the Fast Fourier Transform. The Let's Build series, my personal favorite, showcases the inner workings of everything from reference counting to NSDictionary to tagged pointers.

    Volume II was originally intended to contain all articles through 2016. As I worked on the book, I realized that it was much too big. Although it's primarily an e-book, I like having a print edition available, and finding a print-on-demand service for such a large book proved to be impossible. I solved the problem by splitting the content into Volumes II and III to be released simultaneously. This is the first half of what was going to be that one gigantic book.

    One big change in Volume II is that Friday Q&A is no longer a solo effort. Guest authors Gwynne Raskind and Chris Liscio also have articles in this collection. Gwynne and Chris are extremely smart people who were able to write about topics I could not personally cover, and I'm extremely pleased to be able to present their articles along my own. Their articles are indicated by bylines under the article title. Articles without bylines are mine.

    I hope you enjoy the unusual and occasionally absurd programming content collected here. As always, if you have an idea for a topic that you'd like to see covered in Friday Q&A, send it in!

    Acknowledgements

    Special thanks go to Chris Liscio and Gwynne Raskind, who contributed articles included in this book. Letting someone write for your blog is like letting them stay in your house and borrow your car, and they lived up to the trust I placed in them and then some.

    I would like to thank my reviewers, whose valuable input dramatically improved this book. They are: Harry Jordan, Steven Vandeweghe, Matthias Neeracher, Phil Holland, Matthias Neeracher, Alex Blewitt, Landon Fuller, Joshua Pokotilow, and Cédric Luthi.

    I would also like to thank everyone who contributed the topic ideas used throughout this book. Their names can be found at the beginning of each chapter.

    Finally, I would like to thank everyone who has commented on one of my posts, e-mailed about Friday Q&A, or merely read it. No matter what your contribution, it is appreciated.

    Dedication

    The Complete Friday Q&A Volumes II and III are dedicated to the memory of my friend and fellow glider club member Steve Zaboji. Steve was killed in a plane crash the same afternoon that I received the proofs of these books. He was a central part of the club and will be deeply missed.

    Friday Q&A 2010-11-06:

    Creating Classes at Runtime in Objective-C

    Friday Q&A is back! I had some very important slacking to take care of for the past couple of months, but now I'm ready to resume business as usual. For this return to Friday Q&A, I'm going to talk about how to create Objective-C classes at runtime, a topic suggested by Kevin Avila. This topic is meaty enough that this will be a two-parter; today's post will talk about the basics of how to create classes at runtime, and then the next one will discuss uses for such classes and how to take advantage of them.

    MAObjCRuntime

    One of the things I did during my off time was build

    MAObjCRuntime

    , a nice OO wrapper around a lot of common runtime functionality, including everything that I'm going to talk about today. For my discussion today I will not involve

    MAObjCRuntime

    , so that you can see how to use the runtime directly.

    If you decide to use these techniques on your own, I'd recommend using

    MAObjCRuntime

    instead, as it makes life considerably easier.

    What and Why

    What exactly does it mean to create a class at runtime? If you've done any Objective-C at all, you know what it means to create a class. You create an

    @interface

    block, an

    @implementation

    block, add instance variables and methods, and you have a class that you can use.

    Creating a class at runtime gives you the same result. The difference is that you write code which calls into the runtime to create class structures in memory directly, rather than writing classes to be interpreted by the compiler. You can add methods and instance variables just as you would normally.

    Why would you do such a thing? It's often handy to create new classes at runtime to override functionality in arbitrary classes. For example,

    MAZeroingWeakRef

    does this in order to catch memory management events in order to implement zeroing weak references.

    Creating a Class

    The act of creating a class is accomplished using the

    objc_allocateClassPair

    function in

    objc/runtime.h

    . You pass it a superclass, a name, and a size for per-class storage (generally best left at

    0

    ), and it returns a class to you:

    Class

    mySubclass

    =

    objc_allocateClassPair

    ([

    NSObject

    class

    ],

    MySubclass

    ,

    0

    );

    And that's it! Of course this is pretty boring, since the new class doesn't do anything yet. I'll cover how to actually put things into it shortly.

    An aside: why is it called "allocate class pair"? As you probably already know, all Objective-C classes are also Objective-C objects. You can put them in variables, send them messages, add them to arrays, etc. just like you would with any other object. All objects have a class, and the class of a class is called the metaclass. Each class has a unique metaclass, and thus the pair:

    objc_allocateClassPair

    allocates both the class and the metaclass together.

    A full discussion of what the metaclass is and how it works is beyond the scope of this post, but Greg Parker has a good discussion of metaclasses if you're interested in reading more.

    Adding Methods

    You know how to create a class, but it won't do anything interesting unless you actually put things in it.

    Methods are the most obvious things to add to a newly created class. You add methods to a class using the

    class_addMethod

    function in

    objc/runtime.h

    . This function takes four parameters.

    The first two parameters are the class you want to manipulate, and the selector of the method that you want to add. Both of these should be pretty obvious.

    The next parameter is an

    IMP

    . This type is a special Objective-C

    typedef

    for a function pointer. It's defined as:

    typedef

    id

    (

    *

    IMP

    )(

    id

    ,

    SEL

    ,

    ...);

    Objective-C methods take two implicit parameters,

    self

    and

    _cmd

    , which are the first two parameters listed here. The other parameters are not listed, and are up to you.

    To create the

    IMP

    that you pass to this function, implement a function that takes

    id

    self

    and

    SEL

    _cmd

    as its first two parameters. The rest of the parameters are the parameters that the method will take, and the return type is the method return type.

    For example, let's say you wanted to write an

    IMP

    with this signature:

    -

    (

    NSUInteger

    )

    countOfObject:

    (

    id

    )

    obj

    ;

    You'd write the function like this:

    static

    NSUInteger

    CountOfObject

    (

    id

    self

    ,

    SEL

    _cmd

    ,

    id

    obj

    )

    Unfortunately, the type of this function doesn't match the

    IMP

    typedef, so you have to cast it when passing it to

    class_addMethod

    .

    The last parameter is a type encoding string which describes the type signature of the method. This is the string that the runtime uses to generate the

    NSMethodSignature

    that's returned from

    methodSignatureForSelector:

    , among other uses.

    The best way to generate this type encoding string is to retrieve it from an existing class which has a method with the same signature. This way you can just trust the compiler to get it right and don't have to worry about the details of how these strings are put together. For example, the method above has the same signature as

    -[NSArray

    indexOfObject:]

    , so you can retrieve that type encoding string:

    Method

    indexOfObject

    =

    class_getInstanceMethod

    ([

    NSArray

    class

    ],

    @selector

    (

    indexOfObject:

    ));

    const

    char

    *

    types

    =

    method_getTypeEncoding

    (

    indexOfObject

    );

    If no existing class has a matching method, consider writing a small dummy class that does, and then querying it.

    If you absolutely must build your own type encoding string (not recommended), then you can do it using the

    @encode

    directive to generate strings for the individual components, then combine them. Compiler-generated strings also have numeric stack offset information embedded in them, which means that your string won't completely match its output, but it's often good enough.

    The components of a method's type encoding string are simply the

    @encode

    representation of the return type, followed by the argument types, including the two implicit parameters at the beginning:

    NSString

    *

    typesNS

    =

    [

    NSString

    stringWithFormat:

    @%s%s%s%s

    ,

    @encode

    (

    NSUInteger

    ),

    @encode

    (

    id

    ),

    @encode

    (

    SEL

    ),

    @encode

    (

    id

    )];

    const

    char

    *

    typesC

    =

    [

    typesNS

    UTF8String

    ];

    But again, avoid this if it's at all possible.

    Here's a full example of adding a

    description

    method to a newly created class:

    static

    NSString

    *

    Description

    (

    id

    self

    ,

    SEL

    _cmd

    )

    {

    return

    [

    NSString

    stringWithFormat:

    @<%@ %p: foo=%@>

    ,

    [

    self

    class

    ],

    self

    ,

    [

    self

    foo

    ]];

    }

    // add Description to mySubclass

    // grab NSObject's description signature so we can borrow it

    Method

    description

    =

    class_getInstanceMethod

    ([

    NSObject

    class

    ],

    @selector

    (

    description

    ));

    const

    char

    *

    types

    =

    method_getTypeEncoding

    (

    description

    );

    // now add

    class_addMethod

    (

    mySubclass

    ,

    @selector

    (

    description

    ),

    (

    IMP

    )

    Description

    ,

    types

    );

    A bit verbose, but not too difficult at all.

    Adding Instance Variables

    You can add instance variables to a class using the

    class_addIvar

    method.

    The first two parameters to this function are the class to manipulate and the name of the instance variable you want to add. Both are straightforward.

    The next parameter is the size of the instance variable. If you're using a plain C type as the instance variable, then you can simply use

    sizeof

    to get the size.

    Next is the alignment of the instance variable. This indicates how the instance variable's storage needs to be aligned in memory, potentially with padding in between it and the end of the previous instance variable. A trick to this parameter is that it's the log2 of the alignment rather than the alignment itself. Passing

    1

    means aligning it to a 2-byte boundary, passing

    4

    means 16-byte alignment, etc. Since most types want to be aligned to their size, you can simply use

    rint(log2(sizeof(type)))

    to generate the value of this parameter.

    The last parameter is a type encoding string for the parameter. This can be generated using the

    @encode

    directive and giving it the type of the variable that you're adding.

    Here's a full example of adding an

    id

    instance variable:

    class_addIvar

    (

    mySubclass

    ,

    foo

    ,

    sizeof

    (

    id

    ),

    rint

    (

    log2

    (

    sizeof

    (

    id

    ))),

    @encode

    (

    id

    ));

    Accessing Added Instance Variables

    Accessing this newly-added variable is not as easy as it normally would be. You can't just write

    foo

    in your code, because the compiler has no idea that this thing even exists.

    The runtime provides two functions for accessing instance variables:

    object_setInstanceVariable

    and

    object_getInstanceVariable

    . They take an object and a name, and either a value to set, or a place to put the current value. Here's an example of getting and setting the

    foo

    variable constructed above:

    id

    currentValue

    ;

    object_getInstanceVariable

    (

    obj

    ,

    foo

    ,

    &

    currentValue

    );

    // it will be replaced, so autorelease

    [

    currentValue

    autorelease

    ];

    id

    newValue

    =

    ...;

    [

    newValue

    retain

    ];

    // runtime won't retain for us

    object_setInstanceVariable

    (

    obj

    ,

    foo

    ,

    newValue

    );

    Another way is to simply use key-value coding to read and write the instance variable. As long as you don't have a method with the same name, it will directly access the variable's contents. It will also do proper memory management on object-type variables. As a potential downside, it will box primitive values in

    NSValue

    or

    NSNumber

    objects, which could add complication.

    With either technique, don't forget to add a

    dealloc

    method to release your object instance variables.

    If you need per-instance storage, consider using the associated object API (

    objc_setAssociatedObject

    and

    objc_getAssociatedObject

    ) instead of instance variables. It takes care of memory management for you.

    Adding Protocols

    You can add a protocol to a class using

    class_addProtocol

    . This is not usually very useful, so I won't go into how to use it. Keep in mind that this function only declares the class as conforming to the protocol in question, but it doesn't actually add any code. If you want the class to actually implement the methods in a protocol, you have to implement and add those methods yourself.

    Adding Properties

    Although there are plenty of functions for querying the properties of a class, Apple apparently forgot to provide any way to add a property to a class. Fortunately, like protocols, it's not usually very useful to add a property to a class at runtime, so this is not a big loss.

    Registering the Class

    After you're done setting up the class, you have to register it before you can use it. You do this with the

    objc_registerClassPair

    function:

    objc_registerClassPair

    (

    mySubclass

    );

    It's now ready to use.

    Note that you must register a class before you use it, and you can't add any instance variables to a class after you register it. You can add methods to a class after registration, however.

    Using the Class

    Once you've registered the class, you can message it just like you would any other class:

    id

    myInstance

    =

    [[

    mySubclass

    alloc

    ]

    init

    ];

    NSLog

    (

    @%@

    ,

    myInstance

    );

    You can access the class using

    NSClassFromString

    as well, and in general it behaves just like any other class at this point.

    Friday Q&A 2010-11-19:

    Creating Classes at Runtime for Fun and Profit

    It's time for another edition of Friday Q&A. In the last Friday Q&A, I discussed how to create classes at runtime in Objective-C. Today, I'm going to discuss how to actually make practical use of this technique.

    MAObjCRuntime

    In my last article, I avoided making use of

    MAObjCRuntime

    , my object-oriented wrapper around the Objective-C runtime, in order to show how to use the Objective-C runtime directly. Since I've already shown how to call the runtime directly, I'll be making use of

    MAObjCRuntime

    today in order to make the code simpler to read and write. If you're interested in doing things the old-fashioned way, the

    MAObjCRuntime

    calls translate pretty directly to runtime calls, it's just more verbose and less convenient.

    While I think the calls will be pretty obvious, you may want to read

    MAObjCRuntime

    's readme to see how it works before continuing.

    Conditional Subclassing

    A common problem in Mac and iOS development is supporting multiple OS versions simultaneously. Often it's necessary to use a class that exists on newer versions, but avoid using it on older versions where it's not available. Normally this can be done by using calls like

    NSClassFromString

    . However, sometimes it's necessary to subclass one of these classes, and the normal technique of writing

    @interface

    YourClass

    :

    ThisMightNotExist

    doesn't work too well.

    (It is possible to use the normal syntax by using weak linking to pull in the class which may not exist. Unfortunately, weak linking of Objective-C classes is not very mature yet, and you have to wait for it to work all the way back to the earliest OS version that you support.)

    By creating the subclass at runtime only if the superclass exists, you can make code that works properly in both cases without too much effort.

    As an example, I'll show how to create a subclass of a hypothetical

    NSFoo

    class which might not exist at runtime. The subclass will override a single method from its superclass,

    -bar

    , to do nothing.

    First, write the function that implements the

    -bar

    method. As you'll recall from last time, you just write a C function that takes

    id

    self

    and

    SEL

    _cmd

    as its first two parameters, with the other parameters and the return type as usual. Here's the simple do-nothing function:

    static

    void

    BarOverride

    (

    id

    self

    ,

    SEL

    _cmd

    )

    {

    }

    Now, a function to create the subclass. The first thing it does is use

    rt_createSubclassNamed:

    to make the class.

    static

    Class

    CreateMyFoo

    (

    void

    )

    {

    Class

    NSFoo

    =

    NSClassFromString

    (

    @NSFoo

    );

    if

    (

    !

    NSFoo

    )

    return

    nil

    ;

    Class

    myFoo

    =

    [

    NSFoo

    rt_createSubclassNamed:

    @MyFoo

    ];

    Now to add the new

    -bar

    method. We first get the method from the superclass so I can borrow its type signature string, then create a new

    RTMethod

    and add it to the subclass:

    SEL

    sel

    =

    @selector

    (

    bar

    );

    RTMethod

    *

    nsBar

    =

    [

    NSFoo

    rt_methodForSelector:

    sel

    ];

    RTMethod

    *

    myBar

    =

    [

    RTMethod

    methodWithSelector:

    sel

    implementation:

    (

    IMP

    )

    BarOverride

    signature:

    [

    nsBar

    signature

    ]];

    [

    myFoo

    rt_addMethod:

    myBar

    ];

    That's it! Now just return the newly created class:

    return

    myFoo

    ;

    }

    To complete the code, we just need a simple wrapper function that creates the above class just once and stores it, then returns it on demand. (I'm using GCD for thread safety, which may defeat the purpose of compatibility with older OSes, but it can easily be replaced with another method.)

    static

    Class

    MyFoo

    (

    void

    )

    {

    static

    Class

    c

    =

    nil

    ;

    static

    dispatch_once_t

    pred

    ;

    dispatch_once

    (

    &

    pred

    ,

    ^

    {

    c

    =

    CreateMyFoo

    ();

    });

    return

    c

    ;

    }

    Because

    CreateMyFoo

    returns

    nil

    if

    NSFoo

    doesn't exist,

    MyFoo

    will also return

    nil

    in that case. All the caller has to do to use

    MyFoo

    is something like this:

    Class

    myFoo

    =

    MyFoo

    ();

    if

    (

    myFoo

    )

    {

    id

    foo

    =

    [[

    myFoo

    alloc

    ]

    init

    ];

    // ...

    }

    Calling

    super

    It's very common to call

    super

    in an overridden method. Unfortunately, the

    super

    keyword isn't valid in a C function, even if you're using it to implement an Objective-C method.

    It's still possible, and not too hard, but you have to be a little more roundabout. You need to manually retrieve the method pointer from the superclass, then directly call it. Here's what

    BarOverride

    would look like just calling through to

    super

    :

    static

    void

    BarOverride

    (

    id

    self

    ,

    SEL

    _cmd

    )

    {

    Class

    superclass

    =

    NSClassFromString

    (

    @NSFoo

    );

    void

    (

    *

    superIMP

    )(

    id

    ,

    SEL

    )

    =

    (

    void

    *

    )[

    superclass

    instanceMethodForSelector:

    @selector

    (

    bar

    )];

    superIMP

    (

    self

    ,

    _cmd

    );

    }

    Simply calling through to

    super

    is not all that useful, but you can add your own code before and after the call to augment it.

    Example Subclass

    Here's a more realistic example that subclasses the hypothetical

    NSMysteryView

    to add custom drawing and event handling:

    static

    DrawRect

    (

    id

    self

    ,

    SEL

    _cmd

    ,

    NSRect

    rect

    )

    {

    // draw the original stuff, but on top of a black background

    [[

    NSColor

    blackColor

    ]

    setFill

    ];

    NSRectFill

    (

    rect

    );

    // black background is down, now draw the original

    Class

    superclass

    =

    NSClassFromString

    (

    @NSMysteryView

    );

    void

    (

    *

    superIMP

    )(

    id

    ,

    SEL

    ,

    NSRect

    )

    =

    [

    superclass

    instanceMethodForSelector:

    @selector

    (

    drawRect:

    )];

    superIMP

    (

    self

    ,

    _cmd

    ,

    rect

    );

    }

    static

    MouseUp

    (

    id

    self

    ,

    SEL

    _cmd

    ,

    NSEvent

    *

    event

    )

    {

    // beep if the mouse is clicked in this view

    NSBeep

    ();

    }

    // encapsulate code needed to override an existing method

    static

    void

    Override

    (

    Class

    c

    ,

    SEL

    sel

    ,

    void

    *

    fptr

    )

    {

    RTMethod

    *

    superMethod

    =

    [[

    c

    superclass

    ]

    rt_methodForSelector:

    sel

    ];

    RTMethod

    *

    newMethod

    =

    [

    RTMethod

    methodWithSelector:

    sel

    implementation:

    fptr

    signature:

    [

    superMethod

    signature

    ]];

    [

    c

    rt_addMethod:

    newMethod

    ];

    }

    static

    Class

    CreateMyMysteryView

    (

    void

    )

    {

    Class

    NSMysteryView

    =

    NSClassFromString

    (

    @NSMysteryView

    );

    if

    (

    !

    NSMysteryView

    )

    return

    nil

    ;

    Class

    c

    =

    [

    NSMysteryView

    rt_createSubclassNamed:

    @MyMysteryView

    ];

    Override

    (

    c

    ,

    @selector

    (

    drawRect:

    ),

    DrawRect

    );

    Override

    (

    c

    ,

    @selector

    (

    mouseUp:

    ),

    MouseUp

    );

    return

    c

    ;

    }

    Intercepting Calls with Dynamic Subclassing

    Sometimes you need to intercept a call to an arbitrary object without knowing in advance what it will be. By creating a subclass of the target's class at runtime, and then swizzling the class of the target object, you can accomplish this interception. Cocoa's Key-Value Observing does this, as does my own

    MAZeroingWeakRef

    . Here, I'll walk through how you can do this for yourself. For a simple example, I'll show a sort of light version of what

    MAZeroingWeakRef

    does by making code that simply observes when an object is deallocated by overriding its

    dealloc

    method.

    A quick note: none of the code that I'm going to show is thread safe, just to keep it simple. Since this is the sort of low-level code that you might want to use from multiple threads (especially since

    dealloc

    could happen on other threads), keep in mind that a more practical version would want to lock access to all of the shared data.

    When the object is about to be destroyed, it will post a notification. Of course we'll want a constant to hold the notification name:

    NSString

    *

    MyObjectWillDeallocateNotification

    =

    @MyObjectWillDeallocateNotification

    ;

    Now, we only want to create one subclass of any given class. If two objects of the same class are passed in to the system, they should both be swizzled to the same dynamic subclass, rather than creating two identical dynamic subclasses. To accomplish this, we'll keep a dictionary that maps from classes to subclasses. It's also useful to keep a set of the already-created subclasses:

    static

    NSMutableDictionary

    *

    gSubclassesDict

    ;

    static

    NSMutableSet

    *

    gSubclasses

    ;

    Now, a small function to query the dictionary and either return what it contains, or call a function to create the subclass, insert it into the dictionary, and return that:

    static

    Class

    GetSubclassForClass

    (

    Class

    c

    )

    {

    Class

    subclass

    =

    [

    gSubclassesDict

    objectForKey:

    c

    ];

    if

    (

    !

    subclass

    )

    {

    subclass

    =

    CreateSubclassForClass

    (

    c

    );

    [

    gSubclassesDict

    setObject:

    subclass

    forKey:

    c

    ];

    [

    gSubclasses

    addObject:

    subclass

    ];

    }

    return

    subclass

    ;

    }

    Before we can write

    CreateSubclassForClass

    , we need to write a

    dealloc

    override. All this override needs to do is post the notification and then call

    [super

    dealloc]

    . However, calling

    super

    is complicated because not only is this a dynamically allocated class, but one whose superclass isn't known at compile time. Thus we need to perform a search at runtime to find the correct superclass.

    It is not correct to simply use

    [self

    superclass]

    in this case. Although our dynamic subclass is probably the very last class to be set, and so

    [self

    superclass]

    would probably return the correct answer, it's not guaranteed. Some other piece of code (like KVO) could have pulled the same dynamic subclassing trick that we're pulling after we did it, which means their class would be at the bottom instead of our. To be truly robust, we have to search in a loop until we come across a class that has an entry in

    gSubclassesDict

    , and then that is the one where we need to send our

    dealloc

    .

    Here's what the full

    dealloc

    override function looks like:

    static

    void

    Dealloc

    (

    id

    self

    ,

    SEL

    _cmd

    )

    {

    [[

    NSNotificationCenter

    defaultCenter

    ]

    postNotificationName:

    MyObjectWillDeallocateNotification

    object:

    self

    ];

    Class

    c

    =

    [

    self

    rt_class

    ];

    while

    (

    c

    &&

    !

    [

    gSubclassesDict

    objectForKey:

    c

    ])

    c

    =

    [

    c

    superclass

    ];

    // if it wasn't found, something went horribly wrong

    assert

    (

    c

    );

    void

    (

    *

    superIMP

    )(

    id

    ,

    SEL

    )

    =

    [

    c

    instanceMethodForSelector:

    @selector

    (

    dealloc

    )];

    superIMP

    (

    self

    ,

    _cmd

    );

    }

    Now we're ready to write

    CreateSubclassForClass

    . There's nothing complex here, this looks just like the other subclass-creation code we've written:

    static

    Class

    CreateSubclassForClass

    (

    Class

    c

    )

    {

    // give the subclass a sensible name

    NSString

    *

    name

    =

    [

    NSString

    stringWithFormat:

    @%@_MyDeallocNotifying

    ,

    [

    class

    name

    ]];

    Class

    subclass

    =

    [

    c

    rt_createSubclassNamed:

    name

    ];

    // use the Override function from above

    Override

    (

    c

    ,

    @selector

    (

    dealloc

    ),

    Dealloc

    );

    return

    subclass

    ;

    }

    Finally, a function to transform an object to post this notification. We start out by checking to see if it's already been added by seeing if it has one of our subclasses in its hierarchy:

    void

    MakeObjectPostDeallocNotification

    (

    id

    obj

    )

    {

    Class

    c

    =

    [

    obj

    rt_class

    ];

    while

    (

    c

    &&

    !

    [

    gSubclasses

    containsObject:

    c

    ])

    c

    =

    [

    c

    superclass

    ];

    // if we found one, then nothing else to do

    if

    (

    c

    )

    return

    ;

    // not yet set, grab the subclass

    c

    =

    GetSubclassForClass

    ([

    obj

    rt_class

    ]);

    // set the class of the object to the subclass

    [

    obj

    rt_setClass:

    c

    ];

    }

    That's it! You can now call

    MakeObjectPostDeallocNotification(obj)

    and then use

    NSNotificationCenter

    to listen for the notification.

    Caveats

    There are some gotchas to this technique. From easiest to hardest:

    Archiving: if a targeted object is archived, the archiver will record the custom subclass. When unarchiving, it will try to instantiate that custom subclass. Since these classes are created dynamically, that class may not exist yet, preventing the unarchiver from instantiating the object. To fix this, you can override

    classForCoder

    in the subclass to return the superclass, so that the archiver records the correct class.

    KVO subclasses: as I mentioned previously, KVO makes use of this same technique. Unfortunately, Apple's code does not tolerate having subclasses created beneath its own custom classes. To work around this, you can subclass the real class and then insert your new subclass into the class hierarchy between the KVO class and the real class.

    MAZeroingWeakRef

    shows how to do this, just search for KVO.

    CoreFoundation bridged classes: due to how toll-free bridging is implemented, you cannot subclass the bridged classes, nor can you reliably intercept messages to them in other ways. Depending on exactly what you're doing, you may be able to use some really nasty hacks, but in general your best bet is to simply not try to mess with bridged classes.

    Conclusion

    Creating classes at runtime is a powerful technique. Today I've shown how you can use it to create subclasses of classes that you can't reference at compile time, and to dynamically create subclasses of arbitrary classes in order to intercept calls to them. This is the sort of thing you can use to blow a very large hole in your foot, but it can also let you do things that simply can't be done otherwise.

    Friday Q&A 2010-12-03:

    Accessors, Memory Management, and Thread Safety

    Related Articles

    Custom Object Allocators in Objective-C

    A Tour of OSAtomic

    The Inner Life of Zombies

    Let's Build Reference Counting

    Automatic Reference Counting

    Fork Safety

    Ring Buffers and Mirrored Memory: Part I

    Ring Buffers and Mirrored Memory: Part II

    Nib Memory Management

    It's once again time for a brand new edition of Friday Q&A. This week, I'm going to talk about accessors, and how to properly deal with memory management and thread safety when creating them, a topic suggested by Daniel Jalkut.

    More Complicated Than You Might Think

    Cocoa's reference counting memory management usually works pretty well, and for the most part accomplishes its goal of making memory management decisions a local, rather than global, affair.

    There's a big exception. Spot the bug in this code:

    NSMutableDictionary

    *

    dict

    =

    ...;

    id

    obj

    =

    [

    dict

    objectForKey:

    @foo

    ];

    [

    dict

    removeObjectForKey:

    @foo

    ];

    [

    obj

    something

    ];

    This bug isn't too hard to find. By removing

    obj

    from

    dict

    , you've potentially destroyed the object, which then causes your program to crash on the last line.

    Of course, this bug isn't always this easy to find. The removal may be buried several method calls deep, and the object may sometimes be retained elsewhere, hiding the bug and making your program crash only inconsistently.

    The same problem can happen with a regular object and accessors:

    id

    obj

    =

    [

    otherObj

    foo

    ];

    [

    otherObj

    setFoo:

    newFoo

    ];

    [

    obj

    something

    ];

    // crash

    This is not necessarily a problem. It all depends on how exactly

    -foo

    and

    -setFoo:

    are implemented.

    Basic Accessors

    The most basic accessors look something like this:

    -

    (

    void

    )

    setFoo:

    (

    id

    )

    newFoo

    {

    [

    newFoo

    retain

    ];

    [

    _foo

    release

    ];

    _foo

    =

    newFoo

    ;

    }

    -

    (

    id

    )

    foo

    {

    return

    _foo

    ;

    }

    With these basic accessors, the example is buggy and must be avoided.

    This does not mean that these basic accessors are wrong. It does mean that you need to be more careful when writing code that uses them:

    id

    obj

    =

    [[

    otherObj

    foo

    ]

    retain

    ];

    [

    otherObj

    setFoo:

    newFoo

    ];

    [

    obj

    something

    ];

    // safe

    [

    obj

    release

    ];

    Since most code doesn't set new values before using the old ones, most code won't need to worry about the problem at all. However, since you do sometimes write code like this, you do need to keep this problem in mind, and code accordingly.

    Autoreleasing Accessors

    Rather than make callers retain and release temporary objects, another approach is to modify the accessors to use

    autorelease

    . You can do this in the setter:

    -

    (

    void

    )

    setFoo:

    (

    id

    )

    newFoo

    {

    [

    _foo

    autorelease

    ];

    _foo

    =

    [

    newFoo

    retain

    ];

    }

    However, this still leaves you vulnerable to a crash if there's a temporary autorelease pool set up when the setter is called. It's better to do it in the getter instead:

    -

    (

    id

    )

    foo

    {

    return

    [[

    _foo

    retain

    ]

    autorelease

    ];

    }

    This

    retain

    /

    autorelease

    combo keeps the object alive even after the setter releases it.

    This solves the problem, but there are a couple of downsides. The obvious one is that it's less efficient. Using

    autorelease

    is a bit slower than

    release

    , and it keeps the target object alive longer, which could lead to more memory usage. This isn't usually very important, but it's something to keep in mind.

    More importantly, pervasive use of

    autorelease

    can make it harder to track down memory management errors. If you over-

    release

    an object, you want to crash as soon as possible. Using

    autorelease

    can often cause the crash to be in

    NSAutoreleasePool

    code, making it considerably harder to track down. Using zombies and Instruments will help a lot, but it can still make your job harder.

    Thread Safe Accessors

    When writing thread safe accessors, the

    autorelease

    getter becomes mandatory. Another thread could call the setter after it returns, and the

    retain

    /

    autorelease

    dance is the only way to ensure that this does not destroy the previous object in the middle of being used.

    Thread safe accessors, like any access to shared data, need to use a lock. You can use

    @synchronized(self)

    , an instance of

    NSLock

    , or whatever other locking mechanism you prefer.

    (Lockless access to shared data is, of course, possible, but far too tricky and difficult to cover here. Better to skip it and use locks.)

    By locking all shared access, and by using the

    autorelease

    version of the getter, you end up with thread safe accessors:

    -

    (

    void

    )

    setFoo:

    (

    id

    )

    newFoo

    {

    [

    newFoo

    retain

    ];

    @synchronized

    (

    self

    )

    {

    [

    _foo

    release

    ];

    _foo

    =

    newFoo

    ;

    }

    }

    -

    (

    id

    )

    foo

    {

    id

    returnFoo

    ;

    @synchronized

    (

    self

    )

    {

    returnFoo

    =

    [

    _foo

    retain

    ];

    }

    return

    [

    returnFoo

    autorelease

    ];

    }

    The locking adds a performance penalty and increases the complexity of the code, so you should only use this style when you need it.

    Do You Need Thread Safe Accessors?

    In almost every case, the answer to this question is no. Accessors are usually not the right place to worry about thread safety.

    The problem is that thread safety isn't a composable attribute. If you take a bunch of thread safe components and bundle them together, the result may not be thread safe.

    For a simple example, imagine a

    Person

    class with properties for the first and last name of the person it represents. One thread does this:

    [

    person

    setFirstName:

    @John

    ];

    [

    person

    setLastName:

    @Doe

    ];

    While another thread does this:

    NSString

    *

    f

    =

    [

    person

    firstName

    ];

    NSString

    *

    l

    =

    [

    person

    lastName

    ];

    NSString

    *

    fullName

    =

    [

    NSString

    stringWithFormat:

    @%@ %@

    ,

    f

    ,

    l

    ];

    Thread safe accessors will keep this code from crashing, but it does not protect against an inconsistent result! If the previous name was Bob Smith, this code could easily result in a

    fullName

    of John Smith, which doesn't correspond to either person.

    In order to make this code safe, thread safety needs to be applied at a higher level. For example, you might have a

    PersonDatabase

    object which could be locked and unlocked for any manipulations. You might decree that all

    Person

    access go through a single serial Grand Central Dispatch queue. You might just make all

    Person

    access happen on the main thread.

    No matter which solution you pick, once you've picked it, the thread safe accessors are no longer necessary. The larger-scale thread safety takes care of problems, and all the thread safe accessors do is make your code unnecessarily slow and complex.

    There are cases where a thread safe accessor is useful. You may have a single property that's accessed from many threads and which won't experience problems being inconsistent with other properties, in which case you'd want a thread safe accessor. However, 99% of the time there is no point in making them.

    Properties and

    nonatomic

    Given the above, it's extremely puzzling that Apple has made

    @property

    declarations default to

    atomic

    . Most of the time it's pointless, and it can give the mistaken impression that the programmer doesn't have to worry about thread safety anymore, because the

    @property

    handles it all.

    The

    @property

    and

    @synthesize

    constructs can be a good way to generate accessors without writing code, just be aware that the default

    atomic

    behavior is not all that useful, and doesn't mean you can forget about thread safety.

    Garbage Collection

    [Objective-C garbage collection is no longer supported by Apple, so this section is highly obselete. Consider it to be a little piece of history.]

    If you're using garbage collection, this whole question becomes vastly simpler. Here's what a correct, thread safe accessor pair looks like in garbage collected code:

    -

    (

    void

    )

    setFoo:

    (

    id

    )

    newFoo

    {

    _foo

    =

    newFoo

    ;

    }

    -

    (

    id

    )

    foo

    {

    return

    _foo

    ;

    }

    The lack of explicit memory management calls really simplifies accessors here.

    Conclusion

    Writing accessors is easy, but there are some subtleties. The vast majority of the time, a plain

    retain

    /

    release

    setter and a

    return

    _ivar

    getter is all you need. However, depending on your situation and your individual taste, you may want to put

    retain

    /

    autorelease

    into the getter in order to simplify the code that calls it.

    When it comes to thread safety, accessors are usually the wrong place to worry about it. While there are legitimate cases where it's useful, most of the time you should back up and take on the problem of thread safety at a higher level of your code. And don't let the

    atomic

    @property

    keyword fool you: it doesn't do anything special in this regard.

    If you're coding exclusively for garbage collection, you can pretty much forget about this whole business and write much simpler code.

    Friday Q&A 2010-12-17:

    Custom Object Allocators in Objective-C

    Related Articles

    Accessors, Memory Management, and Thread Safety

    The Inner Life of Zombies

    Let's Build Reference Counting

    Automatic Reference Counting

    Ring Buffers and Mirrored Memory: Part I

    Ring Buffers and Mirrored Memory: Part II

    Nib Memory Management

    Merry holidays, happy winter, and a joyous Friday Q&A to you all. Camille Troillard suggested that I discuss how to create custom object memory allocators in Objective-C, and today I'm going to walk through how to accomplish this and why you might want to.

    What It Means

    As anyone who uses Objective-C knows, you allocate an instance of a class by writing

    [MyClass

    alloc]

    . Creating a custom allocator simply means that replace the standard allocator so that

    [MyClass

    alloc]

    calls into your own code instead.

    An Objective-C object is just a chunk of memory with the right size, and with the first pointer-sized chunk set to point at the object's class. A custom allocator thus needs to return a pointer to a properly-sized chunk of memory, with the class filled out appropriately.

    Why It's Useful

    By far the largest reason to write a custom allocator is for performance. The standard allocator makes tradeoffs which may not be appropriate for your particular case. It also has to work with every class in every situation, whereas your custom allocator only needs to work with your class and the situations it's used in.

    Another reason is overhead. The standard allocator requires a certain amount of extra storage for each allocation for various reasons. This can be particularly expensive for very small objects allocated in very large numbers. A custom allocator can cut down on this overhead substantially by tailoring it to the needs of the class it's written for.

    A Basic Custom Allocator

    The

    +alloc

    method actually just calls through to

    +allocWithZone:

    . Although memory zones are pretty much just a historical curiosity at this point, they remain in the API. Thus the method to override is

    +allocWithZone:

    +

    (

    id

    )

    allocWithZone:

    (

    NSZone

    *

    )

    zone

    {

    For a simple allocator example, I'll just call

    calloc

    . This will have roughly zero advantages over the standard allocator, but shows how it can be done. (I'm using

    calloc

    instead of

    malloc

    because Objective-C code assumes that instance variables are zeroed out.)

    In order to call

    calloc

    , you need to know how much memory to allocate. Fortunately, the Objective-C runtime makes it easy. The

    class_getInstanceSize

    function will tell you exactly this:

    id

    obj

    =

    calloc

    (

    class_getInstanceSize

    (

    self

    ),

    1

    );

    Next, you need to set the isa of this newly-allocated object. The isa is found right at the beginning of the object, and a bit of judicious casting lets you set it easily:

    *

    (

    Class

    *

    )

    obj

    =

    self

    ;

    You can now return the newly created object:

    return

    obj

    ;

    }

    We're not done yet. We also have to override

    -dealloc

    to call

    free

    :

    -

    (

    void

    )

    dealloc

    {

    free

    (

    self

    );

    Normally this would be all. However, the compiler has a warning for

    -dealloc

    methods that don't call through to

    super

    . In order to shut up this warning, I insert a dummy call after a

    return

    statement which prevents it from executing:

    return

    ;

    [

    super

    dealloc

    ];

    // shut up compiler

    }

    Your custom allocator is all ready to go.

    Gotchas

    As with most things at this level, there are a few things to watch out for.

    First, don't do this unless you subclass

    NSObject

    directly. The

    -dealloc

    method covers both destroying the object itself, and freeing resources it holds.

    -[NSObject

    dealloc]

    just destroys the object (mostly) so it's safe not to call it. It's not safe to do this for any other class, though. For example, if you tried this with an

    NSView

    subclass, you'd end up leaking a whole bunch of internal state.

    Second, the mostly from above means there are some things that

    NSObject

    does that you need to think about. One is removing associated objects. If your objects may have associated objects, or you think there's even a chance that it might, then you need to make sure they're removed. This can be done by calling

    objc_removeAssociatedObjects(self)

    . The other is calling destructors for C++ objects in instance variables. Your best bet here is to just avoid having C++ objects as instance variables. If you must have them, look into the possibility of calling or imitating the private runtime function

    objc_destructInstance

    , which takes care of both C++ destructors and associated objects.

    Third, memory debugging tools like ObjectAlloc and zombies won't work on objects with a custom allocator. For this reason, I recommend that you have a memory debugging preprocessor define which makes your objects use the standard allocator instead of your custom allocator, so that you can flip the switch and use these tools if need be.

    Caching Objects

    For a realistic example, I'll write an allocator that places destroyed objects in a cache so that they can be quickly reused. This sort of thing is useful for classes which are allocated and destroyed so frequently that the standard allocator is too slow.

    In order to reach maximum speed, I'll make a few assumptions about how this class works and is used:

    It is never subclassed, or if it is, subclasses never add instance variables. (This allows it to put all instances in the same cache.)

    Its initializer methods can deal with a dirty object; i.e. the instance variables don't need to be zeroed out. (This saves time zeroing out each instance when pulling it out of the cache.)

    It is only ever allocated and destroyed from the same thread. (This makes it unnecessary to create a thread-safe cache.)

    I'll ignore just how the cache works for now, and just assume it presents a simple interface of two functions:

    AddObjectToCache

    and

    GetObjectFromCache

    . The

    +allocWithZone:

    override then looks like this:

    +

    (

    id

    )

    allocWithZone:

    (

    NSZone

    *

    )

    zone

    {

    id

    obj

    =

    GetObjectFromCache

    ();

    if

    (

    obj

    )

    *

    (

    Class

    *

    )

    obj

    =

    self

    ;

    else

    obj

    =

    [

    super

    allocWithZone:

    zone

    ];

    return

    obj

    ;

    }

    The

    -dealloc

    override simply returns the object to the cache:

    -

    (

    void

    )

    dealloc

    {

    // release any ivars here

    AddObjectToCache

    (

    self

    );

    // shut up the compiler

    return

    ;

    [

    super

    dealloc

    ];

    }

    The cache itself is just a linked list, using the

    isa

    slot of each object to point to the next entry in the list. The list head is a global variable:

    static

    id

    gCacheListHead

    ;

    Next, I want a couple of helper functions for accessing the

    next

    pointer of each list item:

    static

    id

    GetNext

    (

    id

    cachedObj

    )

    {

    return

    *

    (

    id

    *

    )

    cachedObj

    ;

    }

    static

    void

    SetNext

    (

    id

    cachedObj

    ,

    id

    next

    )

    {

    *

    (

    id

    *

    )

    cachedObj

    =

    next

    ;

    }

    With these helpers, the two main cache functions are easy to write:

    static

    id

    GetObjectFromCache

    (

    void

    )

    {

    id

    obj

    =

    gCacheListHead

    ;

    if

    (

    obj

    )

    gCacheListHead

    =

    GetNext

    (

    obj

    );

    return

    obj

    ;

    }

    static

    void

    AddObjectToCache

    (

    id

    obj

    )

    {

    SetNext

    (

    obj

    ,

    gCacheListHead

    );

    gCacheListHead

    =

    obj

    ;

    }

    With this system in place, objects are initially allocated normally, but then go into the cache when destroyed. Once the cache has objects, new objects come out of it, which is much faster than allocating new memory.

    Custom Block Allocator

    Caching objects can be a big speed boost, but the initial allocations are not accelerated, and you still have the space overhead of all of those small allocations. By allocating a large block of memory and chopping it up into chunks, it's possible to speed up the initial allocations and vastly decrease the per-object overhead. To do this, I'll use the same object cache scheme as above, but with a modification to the

    +allocWithZone:

    implementation:

    +

    (

    id

    )

    allocWithZone:

    (

    NSZone

    *

    )

    zone

    {

    id

    obj

    =

    GetObjectFromCache

    ();

    if

    (

    !

    obj

    )

    {

    AllocateNewBlockAndCache

    (

    self

    );

    obj

    =

    GetObjectFromCache

    ();

    }

    *

    (

    Class

    *

    )

    obj

    =

    self

    ;

    return

    obj

    ;

    }

    All of the interesting stuff will then happen in

    AllocateNewBlockAndCache

    . The first thing this function will do is allocate a large block of memory. I chose

    4096

    for the block size as it matches the page size used by OS X and is a convenient number to work with:

    static

    void

    AllocateNewBlockAndCache

    (

    Class

    class

    )

    {

    static

    size_t

    kBlockSize

    =

    4096

    ;

    char

    *

    newBlock

    =

    malloc

    (

    kBlockSize

    );

    Once it has this block, it needs to chop it into pieces and add each piece to the cache. To do this, it will walk through the block using

    class_getInstanceSize

    to mark off each instance-sized section, and then use

    AddObjectToCache

    to get each section into the cache:

    int

    instanceSize

    =

    class_getInstanceSize

    (

    class

    );

    int

    instanceCount

    =

    kBlockSize

    /

    instanceSize

    ;

    while

    (

    instanceCount

    --

    >

    0

    )

    {

    AddObjectToCache

    ((

    id

    )

    newBlock

    );

    newBlock

    +=

    instanceSize

    ;

    }

    }

    That's all there is to it. The object caching mechanism takes care of recycling old objects so that they can be used again.

    Conclusion

    Writing a custom object allocator in Objective-C is relatively simple. The hard part is the allocator itself, which is largely up to you. Once you have the allocator, you can plug it into your Objective-C class by:

    Overriding

    +allocWithZone:

    to call your custom allocator, set the

    isa

    of the block to

    self

    , and optionally zero out the rest of the memory.

    Overriding

    -dealloc

    to call your custom allocator, and do not call through to

    super

    .

    Calling

    objc_removeAssociatedObjects

    in

    -dealloc

    if there's a chance of your object containing associated objects.

    Only subclassing

    NSObject

    directly, and not subclassing any subclass of

    NSObject

    .

    In addition to a full-blown custom allocator, techniques like object caching can give you a speed boost with less complexity.

    Friday Q&A 2010-12-31:

    C Macro Tips and Tricks

    Related Articles

    Compile-Time Tips and Tricks

    Namespaced Constants and Functions

    Things You Never Wanted To Know About C

    The year is almost over, but there's time for one last Friday Q&A before 2011 comes around. For today's post, fellow Amoeba Dan Wineman suggested that I discuss tricks for writing macros in C.

    Preprocessor vs Compiler

    To properly understand C macros, you must understand how a C program is compiled. In particular, you must understand the different things that happen in the preprocessor and in the compiler.

    The preprocessor runs first, as the name implies. It performs some simple textual manipulations, such as:

    Stripping comments.

    Resolving

    #include

    directives and replacing them with the contents of the included file.

    Evaluating

    #if

    and

    #ifdef

    directives.

    Evaluating

    #define

    s.

    Expading the macros found in the rest of the code according to those

    #define

    s.

    It is, of course, these last two which are most relevant to today's discussion.

    Note that the preprocessor largely has no understanding of the text that it processes. There are some exceptions to this. For example, it knows that this is a string, and so does not expand the macro inside it:

    #define SOMETHING hello

    char

    *

    str

    =

    SOMETHING, world!

    // nope

    And it can count parentheses, so it knows that this comma does not result in two arguments to the macro:

    #define ONEARG(x) NSLog x

    ONEARG

    ((

    @hello, %@

    ,

    @world

    ));

    But in general, it does not have any concept of what it processes. For example, you can't use

    #if

    to check whether a type is defined or not:

    // makes no sense

    #ifndef MyInteger

    typedef

    int

    MyInteger

    #endif

    The

    #ifndef

    always comes out true even if the

    MyInteger

    type is already defined. Type definitions are evaluated as part of the compilation phase, which hasn't even happened yet.

    Likewise, there is no need for the contents of a

    #define

    to be syntactically correct on their own. It is completely legal, although a poor idea, to create macros like this:

    #define STARTLOG NSLog(

    #define ENDLOG , @testing);

    STARTLOG

    @just %@

    ENDLOG

    The preprocessor just blindly replaces

    STARTLOG

    and

    ENDLOG

    with their definitions. By the time the compiler comes along to try to make sense of this code, it actually does make sense, and so it compiles as valid code.

    A Word of Warning

    C macros are at the same time too powerful and not powerful enough. Their somewhat ad-hoc nature makes them dangerous, so treat them with care.

    The C preprocessor is nearly Turing-complete. With a simple driver, you can compute any computable function using the preprocessor. However, the contortions required to do this are so bizarre and difficult that they make Turing-complete C++ templates look simple by comparison.

    While powerful, macros are also very simple. Since macro expansion is a simple textual process, there are pitfalls. For example, operator precedence can be dangerous:

    #define ADD(x, y) x+y

    // produces 14, not 20

    ADD

    (

    2

    ,

    3

    )

    *

    4

    ;

    #define MULT(x, y) x*y

    // produces 14, not 20

    MULT

    (

    2

    +

    3

    ,

    4

    );

    Be very careful to parenthesize everything that could possibly need it, considering both any possible arguments passed to the macro, and any possible context that the macro could be used in.

    Evaluating a macro argument multiple times can also lead to unexpected results:

    #define MAX(x, y) ((x) > (y) ? (x) : (y))

    int

    a

    Enjoying the preview?
    Page 1 of 1