Tinkering with CompressionLib (Part 3)

18 Jul

Continuing my series on Tinkering with CompressionLib; if you haven’t read my previous posts you can check them out here – Part 1 and Part 2.

Last time when working with CompressionLib I introduced a category on NSData to allow for easy compression / decompression. I initially wrote this in Objective-C.

While working with C libraries in Swift is fairly easy, it’s still nowhere near as easy as dealing with them in Objective-C; largely since you can mix C and Objective-C in the same source file and the fact that C couldn’t hardly care less about type safety.

This time we’re going to take a look at working with CompressionLib from Swift.

// alloc some memory for the stream
let streamPtr = UnsafeMutablePointer<compression_stream>.alloc(1)
var stream    = streamPtr.memory

// the stream’s status
var status : compression_status

// we want to compress so we use the ENCODE option
let op = COMPRESSION_STREAM_ENCODE

// COMPRESSION_STREAM_FINALIZE is used to indicate that no further input will be added. Since we have the entire input data we can finalize right away
// compression_stream_process() expects flags to be an Int32, so we need to convert our flag to that type
let flags = Int32(COMPRESSION_STREAM_FINALIZE.rawValue)

// we want to use the super awesome LZFSE algorithm
let algorithm = COMPRESSION_LZFSE

// init the stream for compression
status = compression_stream_init(&stream, op, algorithm)
guard status != COMPRESSION_STATUS_ERROR else {
    // FIXME: Shame on you for not handling this error properly
    return
}

// setup the stream's source
let inputData   = // get some data
stream.src_ptr  = UnsafePointer<UInt8>(inputData.bytes)
stream.src_size = inputData.length

// setup the stream's output buffer
// we use a temporary buffer to store the data as it's compressed
let dstBufferSize : size_t = 4096
let dstBufferPtr  = UnsafeMutablePointer<UInt8>.alloc(dstBufferSize)
stream.dst_ptr    = dstBufferPtr
stream.dst_size   = dstBufferSize
// and we store the output in a mutable data object
let outputData = NSMutableData()


repeat {
    // try to compress some data
    status = compression_stream_process(&stream, flags)
    
    switch status.rawValue {
    case COMPRESSION_STATUS_OK.rawValue:
        // Going to call _process at least once more
        if stream.dst_size == 0 {
            // Output buffer full...
            
            // Write out to mutableData
            outputData.appendBytes(dstBufferPtr, length: dstBufferSize)
            
            // Re-use dstBuffer
            stream.dst_ptr = dstBufferPtr
            stream.dst_size = dstBufferSize
        }
        
    case COMPRESSION_STATUS_END.rawValue:
        // We are done, just write out the output buffer if there's anything in it
        if stream.dst_ptr > dstBufferPtr {
            outputData.appendBytes(dstBufferPtr, length: stream.dst_ptr - dstBufferPtr)
        }
        
    case COMPRESSION_STATUS_ERROR.rawValue:
        // FIXME: Eat your vegetables; handle your errors.
        return
        
    default:
        break
    }
    
} while status == COMPRESSION_STATUS_OK

// We’re done with the stream - so free it
compression_stream_destroy(&stream)

// Finally we get our compressed data
let compressedData = outputData.copy()

And just like before, when you want to decompress the data you just need to change two variables.

// set the stream operation to decode instead of encode
let op = COMPRESSION_STREAM_ENCODE

// set the flags to 0, we don't need any flags here
let flags = 0

Correction, Stephen Canon points out that you actually can import CompressionLib directly; no need for a bridging header or module work around.

Just use import Compression

Thanks Stephen!

Now there’s one small catch. To be able to work with CompressionLib from Swift you have two options.

The simple way:

#import <compression.h> in an Objective-C bridging header.

The module way:

You can use a module to provide an interface between Swift and the C library. To do this first create a folder in your Project directory. You can name it whatever you like; I named it “CompressionLibModule”.

Next create a text file in the new directory and name it “module.map”

Add the following to the text file

module libcompression [system] {
    header "/Applications/Xcode-beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/include/compression.h"
    export *
}

This creates a module named “libcompression” that contains the compression.h header.

There’s one last step. In the Build Settings for your Project (or Target) under Swift Compiler - Search Paths you need to add the path to your module’s directory to the Import Paths

$(SRCROOT)/CompressionLibModule/

Now in any Swift file you want to use CompressionLib just import libcompression

The module option is quite a bit more work, and I’m sure this will get easier in the future.

So to wrap things up – I’ve rewritten the compression extension in Swift (don’t worry the Objective-C version is still available if you want it).

Here are the Swift versions of the NSData category’s public methods

// Returns a NSData object created by compressing the receiver using the given compression algorithm.
func compressedDataUsingCompression(compression: Compression) -> NSData?

// Returns a NSData object by uncompressing the receiver using the given compression algorithm.
func uncompressedDataUsingCompression(compression: Compression) -> NSData?

To compress some data you just call:

let compressedData = someUncompressedData.compressedDataUsingCompression(Compression.LZFSE)

And to uncompress some data:

let uncompressedData = someCompressedData.uncompressedDataUsingCompression(Compression.LZFSE)

Here’s the repo

 

Tinkering with CompressionLib (Part 2)

16 Jul

After thinking (and writing) a bit about the new CompressionLib available in OS 10.11 (and iOS 9) I’ve continued to play around with it a bit more.

Last time I had looked at the _buffer functions and how they could be used. I remarked, somewhat off handedly, about the inability to get at the expected uncompressed size of an archive and it being a limiting factor. The _buffer functions are simply not meant to be used that way. I do however, still yearn for a CompressionLib style way to get at the archives metadata (assuming the given archive format supports it of course) – I’ll have to give this some more thought.

I largely ignored the stream functions in my first post. This time around I’m going to take a much closer look at them and show how they can be used with NSData. Objective-C is getting some love today.

So, without further ado, let’s dive in.

Say you have an NSData object that contains some raw data, maybe level data for a game, or some other model data that doesn’t change frequently, and you would like to compress it. This is about the simplest case of using compression, but it’s also quite possibly the most common.

Here’s how we can use CompressionLib to compress a NSData object:

// the stream used for compression and it's status
compression_stream stream;
compression_status status;

// we want to compress so we use the ENCODE option
compression_stream_operation op = COMPRESSION_STREAM_ENCODE;

// COMPRESSION_STREAM_FINALIZE is used to indicate that no further input will be added. Since we have the entire input data we can finalize right away
compression_stream_flags flags = COMPRESSION_STREAM_FINALIZE;

// we want to use the super awesome LZFSE algorithm
compression_algorithm algorithm = COMPRESSION_LZFSE;

// init the stream for compression
status = compression_stream_init(&stream, op, algorithm);
if (status == COMPRESSION_STATUS_ERROR) {
    // FIXME: Shame on you for not handling this error properly
}

// setup the stream's source
NSData *inputData = // get some data
stream.src_ptr    = inputData.bytes;
stream.src_size   = inputData.length;

// setup the stream's output buffer
// we use a temporary buffer to store data as it's compressed
size_t   dstBufferSize = 4096;
uint8_t *dstBuffer     = malloc(dstBufferSize);
stream.dst_ptr         = dstBuffer;
stream.dst_size        = dstBufferSize;
// and we store the aggregated output in a mutable data object
NSMutableData *outputData = [NSMutableData new];

do {
    // try to compress some data
    status = compression_stream_process(&stream, flags);
    
    switch (status) {
        case COMPRESSION_STATUS_OK:
            // Going to call _process at least once more
            if (stream.dst_size == 0) {
                // Output buffer is full...
                
                // Write out to outputData
                [outputData appendBytes:dstBuffer length:dstBufferSize];
                
                // Re-use dstBuffer
                stream.dst_ptr = dstBuffer;
                stream.dst_size = dstBufferSize;
            }
            break;
            
        case COMPRESSION_STATUS_END:
            // We are done, just write out the dstBuffer if there's anything in it
            if (stream.dst_ptr > dstBuffer) {
                [outputData appendBytes:dstBuffer length:stream.dst_ptr - dstBuffer];
            }
            break;
            
        case COMPRESSION_STATUS_ERROR:
            // FIXME: Eat your vegetables, handle your errors.
            break;
            
        default:
            break;
    }
} while (status == COMPRESSION_STATUS_OK);

// We're done with the stream so free it
compression_stream_destroy(&stream);

// Finally we get our compressed data
NSData *compressedData = [outputData copy];

When you want to decompress the data you only need to change two variables:

// set the stream operation to decode instead of encode
compression_stream_operation op = COMPRESSION_STREAM_DECODE;

// set the flags to 0, we don't need any flags here
compression_stream_flags flags = 0;

The work involved in setting up a stream for compression / decompression is as minimal as it can be. Like the _buffer APIs, the _stream APIs are very clean and easy to use. In fact, the only stumbling block I ran into was the need to reset the dst_ptr and dst_size during processing to reuse the buffer. I had expected the reuse to be implied and didn’t see anything in the header about this.

With CompressionLib coming standard in the latest SDKs it seems only natural that NSData should support compression and decompression. Compressing some of your app’s data can go a long way to saving valuable space on the user’s device. Not to mention the performance and energy benefits of using compressed data during network transactions. So while I was playing with CompressionLib thats exactly what I did…

Here’s a small category on NSData that adds two public methods

// Returns a NSData object created by compressing the receiver using the given compression algorithm.
- (NSData *)lam_compressedDataUsingCompression:(LAMCompression)compression;

// Returns a NSData object by uncompressing the receiver using the given compression algorithm.
- (NSData *)lam_uncompressedDataUsingCompression:(LAMCompression)compression;

To compress some data you just call:

NSData *compressedData = [someUncompressedData lam_compressedDataUsingCompression:LAMCompressionLZFSE];

And to uncompress some data:

NSData *uncompressedData = [someCompressedData lam_uncompressedDataUsingCompression:LAMCompressionLZFSE];

Here’s the repo.

 

Tinkering with CompressionLib (Part 1)

13 Jul

There is a new system library in OS X 10.11 – CompressionLib.

For the compression algorithm itself CompressionLib exposes 5 choices.

COMPRESSION_LZ4
COMPRESSION_ZLIB
COMPRESSION_LZMA
COMPRESSION_LZ4_RAW
COMPRESSION_LZFSE // Apple specific

lzfse is the interesting one here. It’s an Apple developed algorithm that is faster than, and generally compresses better than zlib (the previous defacto standard). Since it’s Apple specific if you need cross platform support it isn’t for you. For now at least. Nothing has been announced, but I’m very hopeful Apple will choose to open source it. I think it’s in Apple’s best interest to get lzfse used as widely as possible.

CompressionLib’s public interface is small, but nicely thought out. It basically breaks down into two ways of dealing with compression, buffer based and stream based. There are, quite literally, only 7 functions:

compression_encode_buffer
compression_decode_buffer
compression_encode_scratch_buffer_size
compression_decode_scratch_buffer_size

compression_stream_init
compression_stream_process
compression_stream_destory

You can safely ignore the compression_encode_scratch_buffer_size and compression_decode_scratch_buffer_size functions. CompressionLib will automatically create the scratch buffer on your behalf if you pass a NULL scratch buffer to the encode / decode buffer functions. That knocks it down to just 2 functions for buffer based or 3 for stream based.

While watching WWDC ’15 – Session 712 “Low Energy High Performance: Compression and Accelerate” I decided to play around with the buffer functions.

size_t compression_encode_buffer(*dst_buffer, dst_size,
                                 *src_buffer, src_size,
                                 *scratch_buffer,
                                 algorithm)

The encode function compression_encode_buffer, and it’s decode counter part, compression_decode_buffer, take the same parameters and do exactly what you’d expect. You have to specify the dst_buffer‘s size (dst_size). During compression this isn’t a real limitation as you can reasonably expect the worst case scenario to be that the dst_buffer is the same size as the src_buffer (plus a few bytes for overhead when dealing with a very small piece of data). I really like this interface. It helps to make the memory management very clear. You create the buffers, you own them, and it’s your responsibility to free them. You can be reasonably sure of that just by looking at the function prototypes. The argument names also make it very clear exactly what each function needs. No need for a lot of documentation and reading here.

What about decoding?

size_t compression_decode_buffer(*dst_buffer, dst_size,
                                 *src_buffer, src_size,
                                 *scratch_buffer,
                                 algorithm)

This brings me to, what I believe is, a pretty big limitation. When using compression_decode_buffer you don’t have any reasonable expectation of what the uncompressed (dst_buffer) size should be. And if dst_buffer is too small compression_decode_buffer will simply truncate the result to dst_size. This is friendly, at least you don’t have to worry about a buffer overflow. But you must know beyond a reasonable doubt, exactly what size your uncompressed data will be. I halfway expected compression_decode_buffer to return the full size of the uncompressed data so you could increase the dst_buffer size and retry if needed. That would be wasteful, and it doesn’t. compression_decode_buffer returns the size of the data written to the buffer; if it’s truncated it simply returns dst_size. This is pretty clear in the header

@return
The number of bytes written to the destination buffer if the 
input is successfully decompressed. If there is not enough 
space in the destination buffer to hold the entire expanded 
output, only the first dst_size bytes will be written to the 
buffer and dst_size is returned.

I did some digging and couldn’t find any way of getting the expected uncompressed size. I then thought about inspecting the lzfse archive header, but there isn’t any published header spec (at least that I could find – if I’m wrong please let me know @leemorgan).

I think it would be highly beneficial if an API was provided to determine the expected uncompressed buffer size. Perhaps a function like the following:

extern size_t compression_decode_uncompressed_size(const uint8_t * __restrict src_buffer, size_t src_size, compression_algorithm algorithm);

I’ve filed an enhancement request asking for the ability to get the expected uncompressed data’s size. rdar://21787153

With that said, I need to thank Stephen Canon. We had a short conversation on twitter earlier today about CompressionLib and this “limitation”. While playing with CompressionLib I had been focused on lzfse and had neglected to think about how the library needs to provide support for other compression algorithms as well. I had (perhaps incorrectly) assumed that lzfse had this kind of metadata readily available in the archiver’s header. But failed to consider how it would work for archives that don’t have expected uncompressed size stored internally. Stephen pointed out that the _buffer interfaces are very low-level building blocks, and that it’s assumed that the higher level callers will keep this metadata around. The problem with this though, is that the higher level callers will implement this differently (and likely incompatibly). I might write one archiver that stores this data as extended attributes, while someone else might chose to wrap the archive itself with their own header.

But Stephen raises many good points. In lieu of the ability to get at the uncompressed data size directly, I think a standard way of accessing any available headers would be beneficial. This would keep the burden of dealing with the sizes at the higher level caller, while at the same time providing the higher level caller a standard way to get at any headers they might know about and be able to use (such as the uncompressed size).

I readily admit I might be making a bigger deal of this than it needs to be. One could always fall back to the stream functions. But the _buffer functions just look so damn beautiful, I want to use them.

Alara – Accessibility Enabled

10 Jul

Alara 1.1 is now available on the AppStore. I’m proud to say that Alara now fully supports VoiceOver. Accessibility is something I really wanted to get in 1.0, but the schedule just didn’t permit it.

So while 1.0 was waiting in the review queue, I got to work studying how to best bring accessibility support to Alara.

I have to admit something that is a bit shameful of me…I’ve never shipped an app with true accessibility support before. Sure, all apps get some accessibility support for free (big kudos to the Accessibility Team for their hard work there). But to truly be a good citizen, you need to take some time to add specific support.

Which of the Accessibility features you need to support largely depends on the style and usage of your app. If your app is primarily visual, as is the case with Alara, you’ll want to support VoiceOver. This will help users with vision impairments use your app.

When it comes to VoiceOver, the Accessibility Team has really done a lot of the leg work for us. You’ll go a long way by just giving some meaningful labels and traits to your views. You do this either by using the Accessibility Inspection in Interface Builder, or in code by setting the accessibilityLabelaccessibilityValue, accessibilityFrameaccessibilityTraits, and other properties as needed.

The work really comes down to truly understanding how your app works, how it can covey it’s information clearly and concisely, and then expressing that in a style that is more auditory than visual.

Take a look at this screenshot

alaraExample

If you don’t do anything specific to support VoiceOver the app isn’t very helpful. For example, if you were to tap on a bar in the bar-graph you wouldn’t get any information at all. You could tap on the UV index label in the bar (it’ll just read the number aloud), or the time label below it (hearing the time isn’t very helpful without any details). That information is separated and it isn’t very clear as you’re tapping or swiping around what you’re getting at.

In this case it makes more sense to combine these views in the “eyes” of VoiceOver so that they are seen as one entity and when selected reads something aloud like “UV Index 5 at 4PM”.

alaraExampleVoiceOver

I’m not certain I’ve got the wording just right yet and I’ll continue working to make it better as I go. If you’re a user of VoiceOver, or other accessibility features, and have recommendations please let me know either on twitter @leemorgan or email lee@shiftybit.net

The hardest part for me with accessibility was knowing where to get started. I’ll give you a hint. Turn on VoiceOver, launch your app, and start tapping around. You’ll get an idea about what needs a better description pretty quickly. Switch over to Xcode and give them whatever labels you think makes sense right then. Now go back and play with your app for a bit longer. You’ll probably notice all sorts of little things that don’t feel quite right. Maybe some information contained in two views is better understood by combining their description together? Maybe a button shouldn’t be VoiceOver enabled, and instead it’s parent view should be? These are all things you’re likely to think about once you start using your own app with VoiceOver. What are you waiting for? Go ahead, turn it on and play, then get to work. You’re users will thank you.

It’s ok to ship your shitty code (kind of)

8 Jul

Jared Sinclair talks about writing / shipping “shitty code” to keep moving forward.

a fun app has nothing to do with clean code.

I think he’s absolutely right. There’s a time to learn and then there’s a time to ship. Decide which you want to do. It’s likely you’ll also learn quite a bit while shipping your crap code too, which can be applied to your next project.

One word of caution though. While your writing your crap code, you probably want to keep in the back of your mind how you might refactor it later. Don’t worry so much about fixing it now, like Jared said leave a FIXME: comment and move on. Just don’t code yourself into a corner either. The best code isn’t prefect the first time, it’s easily refactorable.

Open Sourcing a Clock

6 Jul

In my ongoing quest to open source more of my work, I’ve open sourced my binary clock app 0’Clock today.

BinaryClockTicking

Admittedly there isn’t much to it. It is just a clock after all. So instead of posting the original Objective-C source, I’ve rewritten it in Swift. If you know someone just getting started with Swift, it might be an easy introduction project. Plus, who doesn’t like a fine binary clock?

One interesting change I decided to make while rewriting it is how to handle setting the LEDs On or Off for a given column. Before I was just using a switch statement, which was easy enough. It went something like this…

func setValue(value: Int, forColumn col: Int) {
    // Turn LEDs for given column OFF
    for row in 0...rows {
        // set LED for row OFF
        setLEDon(false, forColumn: col, row: row)
    }

    // Now turn the desired LEDs ON
    switch value {
        case 1:
        setLEDon(true, forColumn: col, row: 0)
        case 2:
        setLEDon(true, forColumn: col, row: 1)
        case 3:
        setLEDon(true, forColumn: col, row: 0)
        setLEDon(true, forColumn: col, row: 1)
        ...
        case 9:
        setLEDon(true, forColumn: col, row: 0)
        setLEDon(true, forColumn: col, row: 3)
    }
}

While it worked it wasn’t exactly elegant. The logic was easy enough to follow, mainly because there are a small amount of cases and only one kind of action to be taken in each case.

But here’s another way to accomplish the same goal…

func setValue(value: Int, forColumn col: Int) {
    let onesState   = (value & 0b0001) == 0b0001
    let twosState   = (value & 0b0010) == 0b0010
    let foursState  = (value & 0b0100) == 0b0100
    let eightsState = (value & 0b1000) == 0b1000
    
    setLEDon(onesState,   forColumn: col, row: 0)
    setLEDon(twosState,   forColumn: col, row: 1)
    setLEDon(foursState,  forColumn: col, row: 2)
    setLEDon(eightsState, forColumn: col, row: 3)
}

The 0b prefix tells the compiler that the number is binary, instead of a real number like normal.

While we can debate a little over which one is clearer, the second one is more efficient. But let’s be honest, we’re not worried about efficiency in our little clock app. Clarity is much more valuable in this case. But I would argue that once you grasp the basic bitwise operation that is going on here this version is actually clearer. Plus it’s an opportunity to learn a little about bitwise operations, which I just love.

So for those unfamiliar with bitwise operations let’s dive in a see what exactly is going on here. If you already know all about bitwise operations feel free to skip to the bottom for the repo link.

In order to show a number as a binary representation using rows of LEDs we need someway to decide which rows should be lit and which ones should be turned off. In the old way we turned off all the LEDs for a given column and then checked for each possible number 0-9 turning on the corresponding rows as needed. In the new method we’re checking each binary bit of a given number to see if that power of 2 is 1 (On) or 0 (Off) and then turning the LED for that row On or Off to match.

First, a short math refresher is in order…When we say 11 we all know what that means; we learn at a very early age that 11 really means 1 x 10 + 1, or more simply 10 + 1. Let’s take a look at a few more examples…

33
100s 10s 1s
0 3 3
0 x 100 + 3 x 10 + 3 x 1

 

512
100s 10s 1s
5 1 2
5 x 100 + 1 x 10 + 2 x 1

 

We can think about binary numbers in the same basic way; just instead of dealing with powers of 10, we’re dealing with powers of 2. And we indicate that a power of 2 is “On” by showing a 1 in its place, or “Off” by showing a 0 in its place. This is where we get the 1’s and 0’s for binary from.

2
4s 2s 1s
0 1 0
0 x 4  + 1 x 2 + 0 x 1

 

5
4s 2s 1s
1 0 1
1 x 4  + 0 x 2 + 1 x 1

 

Ok, now for a brief discussion about bitwise operations. A bitwise operation is just a way of saying we’re going to manipulate a set of bits in some way. In math we normally talk about operations like addition, subtraction, multiplication, and division. In binary there is a different set of operations we can perform and we call them bitwise operations. These include AND, OR, XOR, NOT, and a few others. But for today we’ll just be discussing AND.

Just like in math were we represent addition with a + symbol we represent the AND operation with the & symbol.

The AND operation takes two bits and if they are both 1 the result will be 1, otherwise the result will be 0. Here’s an example where value is the input number and mask is the binary number we AND it with. This style of using AND is called masking, because we “mask” out the bits we don’t care about, leaving only the bit (or bits) we do care about in the result.

5 & 1 5 & 2 5 & 4 5 & 8
Value 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
Mask 0 0 0 1 0 0 1 0 0 1 0 0 1 0 0 0
Result 0 0 0 1 0 0 0 0  0 1 0 0 0 0 0 0

 

So in that scenario we’re left with 1 is On, 2 is Off, 4 is On, and 8 is Off. Or put more simply 1 + 4, which of course equals 5, the number we gave it.

Ok, with that out of the way, let’s take a look at the code again.

Here’s how the code evaluates out if the value was 5 (or 0101 in binary)

let onesState = (value  & 0b0001) == 0b0001 // step 1
let onesState = (0b0101 & 0b0001) == 0b0001 // step 2
let onesState = 0b0001 == 0b0001            // step 3
let onesState = true                        // result

let twosState = (value  & 0b0010) == 0b0010
let twosState = (0b0101 & 0b0010) == 0b0010
let twosState = 0b0000 == 0b0010
let twosState = false

let foursState = (value  & 0b0100) == 0b0100
let foursState = (0b0101 & 0b0100) == 0b0100
let foursState = 0b0100 == 0b0100
let foursState = true

let eightsState = (value  & 0b1000) == 0b1000
let eightsState = (0b0101 & 0b1000) == 0b1000
let eightsState = 0b0000 == 0b1000
let eightsState = false

So with that we have the following results

setLEDon(onesState,   forColumn: col, row: 0)
setLEDon(twosState,   forColumn: col, row: 1)
setLEDon(foursState,  forColumn: col, row: 2)
setLEDon(eightsState, forColumn: col, row: 3)

Which becomes…

setLEDon(true,  forColumn: col, row: 0)
setLEDon(false, forColumn: col, row: 1)
setLEDon(true,  forColumn: col, row: 2)
setLEDon(false, forColumn: col, row: 3)

This allows us to set the LEDs precisely to the desired state given any number.

Now I’m not arguing that bitwise operations are the solution to all your problems, and it can be easy to create some obscure and complicated code using them. But they are a very valuable tool to have in your toolbox, and, I think, too often over looked.

Here’s the repo on GitHub.

KVC in Swift (Part 2)

3 Jul

Continuing my attempt at making KVC in Swift

First some quick follow-up:

Paul Lynch mentions on twitter that KVC has actually been around since NeXTSTEP 3.3 (or maybe earlier).

David Owens shows us how simple it is to convert the valueForKey: method to generics.


 

This time around we’ll integrate David’s generic functionality, see how subscripting with generics still isn’t quite there, and extend our KVC protocol to implement valueForKeyPath:

First up, switching to generics – where we can.

In our KVC protocol change valueForKey: to the following

func valueForKey(key : String) -> T?

Then in the KVC extension change the valueForKey: default implementation to this:

func valueForKey<T>(key : String) -> T? {

    let mirror = reflect(self)
    
    for index in 0 ..< mirror.count {
        let (childKey, childMirror) = mirror[index]
        if childKey == key {
            return childMirror.value as? T
        }
    }
    return nil
}

You probably noticed the only real difference is replacing Any with T. T is just a placeholder for a type, a generic type if you will. We could have just as well named it MySuperAwesomeGenericType, but we’re not crazy.

Generic functions can work with any type. The actual type that will be used in place of T will be determined each time valueForKey is called. Confusing? Maybe this will help…

Before, if we had called valueForKey: it would return a type of Any.

let s = aValue.valueForKey("someString")

We can’t do anything useful without casting the type.

let s = aValue.valueForKey("someString") as? String

With generics we can write this more naturally and it will return the type we specify.

let s : String? = aValue.valueForKey("someString")

It would be really nice if the compiler could infer the type entirely, but it’s a start.

Unfortunately this doesn’t translate directly to subscripting.

You can’t just switch out the Any? with T? here

subscript (key : String) -> T?

The compiler will complain that it doesn’t know what T is. I think there might be a way around this by using typealias. If you know of a way to make the subscript generic I would love to hear about it (@leemorgan).

OK. Now that we’ve cleaned that up a bit. Let’s take a look at our next method to implement, valueForKeyPath:

Unlike valueForPath: which will only let you get the value of a given object, valueForKeyPath: will evaluate a chain of properties and return the final link’s value.

We’ll get started by adding the prototype to our KVC protocol

func valueForKeyPath<T>(keyPath : String) -> T?

Then in our KVC extension we’ll implement it like so…

func valueForKeyPath<T>(keyPath : String) -> T? {
    
    let keys = split(keyPath.characters){$0 == "."}.map{String($0)}
    var mirror = reflect(self)
    
    for key in keys {
        for index in 0 ..< mirror.count {
            let (childKey, childMirror) = mirror[index]
            if childKey == key {
                if childKey == keys.last {
                    return childMirror.value as? T
                }
                else {
                    mirror = childMirror
                }
            }
        }
    }
    return nil
}

Most of this should look very familiar, but there’s two parts that need explaining…

let keys = split(keyPath.characters){$0 == "."}.map{String($0)}

There’s a lot going on in that line, but once we break it down it’s not that bad.

In Swift 2 you can’t use split() on String anymore. To get around this we use the characters property of String and split whenever we encounter a “.”

Next, since we’re splitting on the characters we need to convert them back into Strings. We use map to return the split character groups as Strings. (Credit to AirSpeedVelocity for detailing this change in Swift 2, and much more here).

The other part we need to explain is the new loop.

for key in keys {
...
if childKey == keys.last { 
    return childMirror.value as? T 
} 
else { 
    mirror = childMirror 
}

This loop steps through each key in the property key chain. If the key is the last key in the chain we return the value like we did before in valueForKey: otherwise we set mirror to point to the child property and continue the loop.

Now we can quickly transverse a chain of properties

struct myValue : KVC {
    let someString = "Hello World"
}

struct myValueHolder : KVC {
    let aValue = myValue()
}
let bValue = myValueHolder()

let c : String? = bValue.valueForKeyPath("aValue.someString")

And if we change our subscript to use valueForKeyPath: instead of valueForKey: we get this ability for free in subscripting as well.

let c : Any? = bValue["aValue.someString"]

And here’s a cool feature; only the root object needs to conform to the KVC protocol. Even if it’s properties, their children, and so on, don’t conform to KVC you can still access them using valueForKeyPath:

This is still more of a proof of concept than anything, but I’m having fun seeing how KVC could be very natural in Swift.

Updated playground on GitHub here.

KVC in Swift (Part 1)

2 Jul

Last year Brent Simmons wrote about the lack of Key-Value-Coding (KVC) in Swift.

KVC has been around for quite awhile now. Taking a look at the NSKeyValueCoding protocol documentation shows it has been around since OS X 10.0. Which is honestly further back than I remember it being.

It’s not a large API, but it can be very useful.

As the docs say, the basic methods for accessing an object’s values are setValue:forKey:, which sets the value for the property identified by the specified key, and valueForKey:, which returns the value for the property identified by the specified key.

Unfortunately you don’t get those methods in Swift classes and Structs. However, It should be noted that any class that inherits from NSObject does still get KVC in Swift.

Brent mentioned that it would be pretty cool and “Swift-like” to have a syntax in Swift like the following

x["propertyName"]

And I completely agree. So let’s have a go at it.

–––––––––––––––––––––––––––––––––––––

First we need to define a struct to play with.

struct myValue {
    let someString = "Hello World"
    let someNumber = 42
}

let aValue = myValue()

Now we can of course access the properties using the normal syntax like

aValue.someString

But if we don’t know the property we want at compile time and instead have the property’s name as a string we need to do some more work to get at it’s value…

Lets define our KVC protocol

protocol KVC {    
    func valueForKey(key : String) -> Any?
}

For now we’re just going to be implementing  valueForKey: which will allow us to get the value of any property.

We’ll go ahead and extend our KVC protocol and add our default implementation.

extension KVC {
    
    func valueForKey(key : String) -> Any? {
    
        let mirror = reflect(self)
        
        for index in 0 ..< mirror.count {
            let (childKey, childMirror) = mirror[index]
            if childKey == key {
                return childMirror.value
            }
        }
        return nil
    }
}

OK. Let’s break this down a bit. The valueForKey: prototype says that we’re going to take a string and return an optional of Any? Unfortunately I don’t know of a way to have it return a generic (See my follow-up post for the generic version). Or a way to extend Any to make KVC available to all Swift types. If you have any advice let me know on twitter @leemorgan.

The next line is really where things start to get interesting.

let mirror = reflect(self)

Take a look at the reflect() function and you’ll see that it takes a generic and returns MirrorType.

Let’s take a quick sidebar to discuss reflect() and MirrorTypeMirrorType says it “supplies an API for runtime reflection”. Well, what does that mean? It simply means it provides some functions that allow you to get information about a given type / object (e.g. Struct or Class).

If you’re coming from Objective-C then you’re likely familiar with methods like isKindOfClass: and respondsToSelector: those methods are a form of Introspection (Introspection refers to the capability of objects to divulge details about themselves as objects at runtime). You can think of Reflection as a somewhat more powerful form of Introspection.

The parts of MirrorType that we’re interested in are

/// The instance being reflected.
    var value: Any { get }

/// The count of `value`'s logical children.
    var count: Int { get }
    subscript (i: Int) -> (String, MirrorType) { get }

Those methods will allow us to find out what properties our struct has and their values.

Back to our KVC protocol…In the next line we are looping though each property in our struct

for index in 0 ..< mirror.count {

We then get a tuple of the property’s name (childKey) and it’s reflected value (childMirror) using MirrorType‘s subscript method. We don’t so much care about the reflected value (childMirror), it’s just a way for us to access the property’s underlying value.

let (childKey, childMirror) = mirror[index]

Next we check to see if the property (childKey) is the one we’re looking for. If it is, we return it’s value.

if childKey == key {
    return childMirror.value
}

Finally, if we don’t find a match we just return nil

return nil

Now to use this we just need to make our myValue struct conform to the KVC protocol.

struct myValue : KVC { 
    let someString = "Hello World" 
    let someNumber = 42 
}

And then we can use KVC like so

let aValue = myValue()
aValue.valueForKey("someString")

Of course this isn’t the pretty syntax like we wanted, but we can get that really easy. Just add this to our KVC extension

subscript (key : String) -> Any? {
    return self.valueForKey(key)
}

And now we can use it like this

aValue["someString"]

If you’re interested, I’ve posted a Playground demonstrating all this on GitHub.

Alara – Enjoy the sun, safely.

2 Jul

A few years ago a friend of mine, whom I served with in the Air Force, was diagnosed with Melanoma. Upon his diagnosis he was medically discharged from service. I won’t go into the details but suffice to say dealing with melanoma has been very difficult for him and his family.

Melanoma is the most dangerous form of skin cancer and is most often caused by ultraviolet radiation from the sun. When people think of skin cancer they tend to dismiss it as something minor, but Melanoma kills a nearly 10,000 people in the US every year. The American Cancer Society estimates that at present, more than 135,000 new cases of melanoma in the US are diagnosed every year. Fortunately, if recognized and treated early, it is almost always curable. One simple step to prevent Melanoma is limiting your exposure to the sun when the UV radiation is high. Unfortunately, you can’t tell what the UV index is just by looking outside. Ozone depletion, as well as seasonal and weather variations, cause different amounts of UV radiation to reach the Earth at any given time. UV radiation can be high on cloudy days and low on sunny days, it isn’t directly related to the weather.

My wife and I are also light skinned and freckled. Melanoma risk is around double in people with freckles, compared with people without freckles. We have to be careful about how much sun exposure we get. But we also love outdoor activities like running, hiking, and going on walks. I often find myself checking the UV index throughout the day to see when the best time is to go outdoors and enjoy the sun.

We wanted an app that would let us see what the UV index is expected to be throughout the day and to suggest how to best protect ourselves at times when the UV rays are most harmful.

Not finding an app that met our needs, I made one.

I’m proud to announce Alara is available on the AppStore.

 

I’m a software developer, and always wished I could make more of a positive impact on peoples lives. I hope Alara helps in some small way.