Caleb Madrigal

Programming, Hacking, Math, and Art

 

NSArray+FP

I realized that I utilize the [NSArray head] and [NSArray tail] functions in various code snippets, but haven.t shared the actual code for that category. So here is my NSArray+FPcode.

NSArray+FP.h

#import <Foundation/Foundation.h>
typedef id(^MapBlock)(id);
@interface NSArray (FP)
- (NSArray *)map:(MapBlock)block;
- (id)head;
- (NSArray *)tail;
@end

NSArray+FP.m

#import "NSArray+FP.h"
@implementation NSArray (FP)

- (NSArray *)map:(MapBlock)block {
    NSMutableArray *resultArray = [[NSMutableArray alloc] init];
    for (id object in self) {
        [resultArray addObject:block(object)];
    }
    return resultArray;
}

- (id)head
{
    return [self objectAtIndex:0];
}

- (NSArray *)tail
{
    NSRange tailRange;
    tailRange.location = 1;
    tailRange.length = [self count] - 1;
    return [self subarrayWithRange:tailRange];
}

@end

Functional programming to deal with asynchronicity in Objective-C

In the last few weeks, I've used the [ALAssetsLibrary loadImages:callback:] method to load a list of images. For what I was doing, I wanted to wait till all the images were loaded before proceeding. I found that I could solve this problem very elegantly using a recursive solution:

- (void)loadImages:(NSArray *)imageUrls loadedImages:(NSArray *)loadedImages 
                                        callback:(void(^)(NSArray *))callback
{
    if (imageUrls == nil || [imageUrls count] == 0) {
        callback(loadedImages);
    }
    else {
        NSURL *head = [imageUrls head];
        __unsafe_unretained id unretained_self = self;        
        ALAssetsLibrary* library = [[ALAssetsLibrary alloc] init];
        [library assetForURL:head resultBlock:^(ALAsset *asset) {
            ALAssetRepresentation *assetRepresentation = asset.defaultRepresentation;

            UIImage *image = [UIImage imageWithCGImage:assetRepresentation.fullResolutionImage 
                              scale:assetRepresentation.scale
                              orientation:(UIImageOrientation)assetRepresentation.orientation];

            [unretained_self loadImages:[imageUrls tail] loadedImages:[loadedImages 
                arrayByAddingObject:image] callback:callback];
        } failureBlock:^(NSError *error) {
            [unretained_self loadImages:[imageUrls tail] loadedImages:loadedImages callback:callback];
        }];
    }
}

In ...

How to reference self in a block in Objective-C

When using ARC (automatic reference counting) in Objective-C, you need to be careful to avoid causing retain cycles. One place where a retain cycle can occur is where self is referenced in a block. To avoid a retain cycle, you can use the __unsafe_unretained modifier as such:

__unsafe_unretained id unretained_self = self;
reachability = [Reachability reachabilityWithHostname:@"maps.google.com"];
reachability.reachableBlock = ^(Reachability *r) {
    dispatch_async(dispatch_get_main_queue(), ^{
        SurveyFormController *myself = unretained_self;
        self.mapView.reachable = YES;
        [myself configureView];
    });
};

String to Base64 String in Objective-C

Today, I needed to convert an ASCII-encoded NSString to a base64 NSString. I found a number of methods that convert from an NSString to a Base64 NSData, or from NSData to a Base64 string, but couldn't find one that did exactly what I needed. So here is a method that simply converts an NSString to a Base64 NSString:

+ (NSString *)base64String:(NSString *)str
{
    NSData *theData = [str dataUsingEncoding: NSASCIIStringEncoding];
    const uint8_t* input = (const uint8_t*)[theData bytes];
    NSInteger length = [theData length];

    static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

    NSMutableData* data = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
    uint8_t* output = (uint8_t*)data.mutableBytes;

    NSInteger i;
    for (i=0; i < length; i += 3) {
        NSInteger value = 0;
        NSInteger j;
        for (j = i; j < (i + 3); j++) {
            value <<= 8;

            if (j < length) {
                value |= (0xFF & input[j]);
            }
        }

        NSInteger theIndex ...

Map in Objective-C

Today, I was faced with an issue several times where I had an array of items of one type, and had to convert this into an array of items of a different type. This made me really want a map() function. So I added one to NSArray like so:

NSArray+FP.h

#import <Foundation/Foundation.h>
typedef id(^MapBlock)(id);
@interface NSArray (FP)
- (NSArray *)map:(MapBlock)block;
@end

NSArray+FP.m

#import "NSArray+FP.h"
@implementation NSArray (FP)
- (NSArray *)map:(MapBlock)block {
    NSMutableArray *resultArray = [[NSMutableArray alloc] init];
    for (id object in self) {
        [resultArray addObject:block(object)];
    }
    return resultArray;
}
@end

So now, I can do this!

NSArray *strArray = [NSArray arrayWithObjects:@"1",@"1",@"2",@"3",@"5",@"8",nil];
NSArray *numArray = [strArray map:^id(id object) {
    NSString *str = object;
    return [NSNumber ...

Force weak reference in Objective-C

Today, I was trying to add an object to an NSDictionary and force it to be a weak reference. This can be done with the [NSValue valueWithNonretainedObject] call:

NSValue *weakRef = [NSValue valueWithNonretainedObject:loadDelegate];
NSDictionary *userInfo = [[NSDictionary alloc] initWithObjectsAndKeys:weakRef, @"loadDelegate", nil];