<![CDATA[Klaus' thoughts on iOS]]>http://www.dudas.co.uk/Ghost v0.4.1Sat, 19 Nov 2016 13:54:21 GMT60<![CDATA[Making KVO safer]]>One of the main issues with KVO is caused by classes not knowing what observers a superclass has registered.
When a subclass also wants to observe the same keyPath they have the danger of removing the observer from the super class.

- (void)someMethod
{
    [self addObserver:self
           forKeyPath:@"view.frame"
              options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial
              context:NULL];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"view.frame"])
    {
        [self viewDidChangeFrame];
    }
    else
    {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

- (void)removeKVO
{
    [self removeObserver:self forKeyPath:@"view.frame"];
}

When super also expects to receive callbacks for view.frame expected behaviour will quickly break and be hard to track down.

To protect against this the context can be used to distinguish between different classes:

static void *HCViewControllerKVOContext = &HCViewControllerKVOContext;
- (void)someMethod
{
    [self addObserver:self
           forKeyPath:@"view.frame"
              options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial
              context:HCViewControllerKVOContext];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if (context == HCViewControllerKVOContext)
    {
        if ([keyPath isEqualToString:@"view.frame"])
        {
            [self viewDidChangeFrame];
        }
    }
    else
    {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

- (void)remoevKVO
{
    [self removeObserver:self forKeyPath:@"view.frame" context:HCViewControllerKVOContext];
}

This will also eliminate calling -[super observeValueForKeyPath:ofObject:change:context:] when the super class doesn't expect it, which will crash.

]]>
http://www.dudas.co.uk/making-kvo-safer/4678fa02-abad-4186-9e5a-1796171d369cThu, 20 Feb 2014 10:34:35 GMT
<![CDATA[NS_REQUIRES_SUPER]]>__attribute((objc_requires_super)) was first introduced as work in progress into CLANG in September 2012 and was documented in October 2013. On both OS X and iOS there is now a NS_REQUIRES_SUPER macro that conditionally wraps the objc_requires_super attribute depending on compiler support. Once a method declaration is appended with this macro, the compiler will produce a warning if super is not called by a subclass overriding the method. E.g.:

@interface KPDObject : NSObject
- (void)reduceSize NS_REQUIRES_SUPER;
@end

@interface KPDDataObject : KPDObject
//...
@end

@implementation KPDDataObject
//...
- (void)reduceSize
{
    [self gzipDataIfNeeded];
}
@end

This will result in a warning: KPDDataObject: Method possibly missing a [super reduceSize] call.

Correctly marking methods with this macro is incredibly useful and should greatly reduce the hard to debug bugs introduced by the lack of calling super.

Intentionally not calling super

NS_REQUIRES_SUPER is great to catch mistakes, but there are always cases when circumstances call for breaking the rules. If you are sure that you don't want to call super you can always temporarily ignore the warning for that method, i.e.:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-missing-super-calls"
- (void)reduceSize
{
    [self gzipDataIfNeeded];
}
#pragma clang diagnostic pop
]]>
http://www.dudas.co.uk/ns_requires_super/d26d6f21-613a-4dc1-bed7-39112aa0d84bSun, 16 Feb 2014 22:50:51 GMT
<![CDATA[Three's LTE Has Finally Arrived]]>After having promised to have LTE available by the end of 2013, today was the day that my account was finally enabled for LTE on Three. While the mast near my home has not yet been upgraded for LTE. The wait was definitely worth it.

47Mbps down - 18Mbps up
This test was conducted in Hammersmith, London on an iPhone 5 using Speedtest.net Mobile Speed Test.

While I was upset that Three took so much longer than they had originally announced, and where generally bad at letting customers know what was going on, now I am happy again.

]]>
http://www.dudas.co.uk/threes-lte/4c10fb42-3c65-4825-80cf-32ed0c736101Wed, 12 Feb 2014 21:19:28 GMT
<![CDATA[AOCUDL - Alternative Objective-C User Defined Literals]]>Alternative Objective-C User Defined Literals

AOCUDL was inspired by Dustin Bachrach's OCUDL.

The purpose of AOCUDL is to provide a simple way to define custom literals for Objective-C. These are correctly typecast, extensible and flexible.

The source is available on GitHub.

To add this to your project using CocoaPods just add the following to your podfile:

pod 'AOCUDL', '~> 1.0'

Example

NSURLRequest *request = $(NSURLRequest)[@"http://hypercrypt.net"];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];

or simply

NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:$(NSURLRequest)[@"http://hypercrypt.net"] delegate:self];

This functionality is provided by using Objective-C subscripting and a small macro to glue the whole thing together:

#define $(cls) (cls *)((id)[cls class])

For a custom class to support AOCUDL all that needs to be implemented is one (or both) of the following methods:

+ (instancetype)objectAtIndexedSubscript:(NSUInteger)index;
+ (instancetype)objectForKeyedSubscript:(id)key;

The default implementation on NSObject is to return nil.

Useful Literals

AOCUDL includes a few literals for built-in classes, they broadly match those included by OCUDL. Examples:

  • NSMutableURLRequest: $(NSMutableURLRequest)[@"http://hypercrypt.net"] - This creates a GET request
  • NSNull: $NSNull or $(NSNull)[any-id-or-NSUInteger]
  • NSSet: $(NSSet)[@[object1, object2, object3]]
  • NSURLRequest: $(NSURLRequest)[@"http://hypercrypt.net"] - This creates a GET request
  • NSURL: $(NSURL)[@"http://hypercrypt.net"]
  • NSUUID: $(NSUUID)[@"8DFD5DF3-6D8B-4DC4-B0A2-1F8ED614FC16"]
  • UIColor: $(UIColor)[0xff0000]
  • UIImage: $(UIImage)[@"testImage"]
  • UINib: $(UINib)[@"AOCUDLViewController"]
  • UIStoryboard: $(UIStoryboard)[@"Main_iPhone"]
]]>
http://www.dudas.co.uk/aocudl/89e71751-13bf-481c-8089-cef5215738ceThu, 05 Dec 2013 21:55:22 GMT
<![CDATA[RE: OCUDL]]>OCUDL: Objective-C User Defined Literals

Recently a GitHub project has been published that aims to introduce custom literals to Objective-C. The syntax is simple: $(#FF0000) would return [UIColor redColor] while $(null) could return NSNull. It also allows classes to register their own mapping. Full details can be found on Dustin Bachrach's post about the OCUDL.

Alternative Syntax Suggestion

While OCUDL syntax is simple, it has a few issues. Firstly, there is no way for the compiler to know the returned object's type. While there is a trend towards using instancetype rather than id for return types, this is a step backwards for type checking. It is made worse as the implementation relies on prefixes and suffixes, something that may clash. I would propose an alternative syntax:

$(NSURL)[@"http://apple.com"];
$(NSURLRequest)[@"http://apple.com"];
$(UIColor)[0xff0000];
$(NSSet)[@[@1, @2, @3]];

This can be implemented with the following macro:

#define $(cls) (cls *)((id)[cls class])

To make a class support the syntax, there is no need to register anything with a manager class, the only thing that needs to be implemented is one or both of the following methods:

+ (id)objectAtIndexedSubscript:(NSUInteger)idx;
+ (id)objectForKeyedSubscript:(id)key;

The NSSet example can easily be implemented in the following way:

@implimentation NSSet (AOCUDL)

+ (id)objectForKeyedSubscript:(id)key
{
    return [self setWithArray:key];
}

@end

This uses the same syntax used for the new object subscripting syntax (e.g NSArray or NSDictionary). This also allows the returned object to be cast to the correct class, allowing for warnings and errors to be correctly generated. It also allows for two classes to respond to the same object in different ways (e.g. NSURL and NSURLRequest above).

]]>
http://www.dudas.co.uk/re-ocudl/a70c0ce3-5156-4933-80da-c84bc7cb78a9Mon, 18 Nov 2013 21:22:18 GMT
<![CDATA[HCViews 1.2 adds UIAlertView (HCContext)]]>HCViews 1.2 was released today. As well as fixing a small bug in HCChevronView it also adds UIAlertView (HCContext)

This adds a context property to UIAlertView to allow an object to be associated with it. The aim is to allow the delegate to perform the appropriate action without having to add a property on the view controller or having to assign arbitrary numbers to the alert view's tag.

1.2 also adds support for Cocoapods subspecs, you can now include just the HCViews that you would like:

pod 'HCViews/HCBlockView', '~> 1.2'
pod 'HCViews/HCChevronView', '~> 1.2'
pod 'HCViews/HCClippingView', '~> 1.2'
pod 'HCViews/UIAlertViewHCContext', '~> 1.2'

or get everything

pod 'HCViews', '~> 1.2'

The full source is available on GitHub

]]>
http://www.dudas.co.uk/hcviews-1-2/e3e8222c-3483-4e91-8846-908af1dc95d4Sat, 16 Nov 2013 17:06:49 GMT
<![CDATA[iPad mini with Retina Display]]>Now that the iPad mini with Retina Display has been released, I ran Geekbench 3 on both the original iPad mini and the new model.

The iPad mini with Retina Display has a 1.3GHz A7 CPU, slightly slower than the iPad Air's 1.4GHz chip. Both iPads have 1GB of memory.

Compared to the original iPad mini the new iPad mini performs amazingly.

Benchmark Results

System Information

iPad mini with Retina Display iPad mini
Operating System iOS 7.0.3 iOS 7.0.3
Model iPad mini with Retina Display iPad mini
Processor ARM @ 1.28 GHz
1 processor, 2 cores
Apple A5 @ 1.00 GHz
1 processor, 2 cores
Processor ID ARM ARMv7
L1 Instruction Cache 64 KB 32 KB
L1 Data Cache 64 KB 32 KB
L2 Cache 1024 KB 1024 KB
L3 Cache 0 KB 0 KB
Motherboard
BIOS
Memory 975 MB 502 MB

Integer Performance

iPad mini with Retina Display iPad mini
Integer 1446 347
Integer Multicore 2832 669
AES 969 20
AES Multicore 1936 40
Twofish 987 290
Twofish Multicore 1935 552
SHA1 4375 438
SHA1 Multicore 8601 862
SHA2 2348 666
SHA2 Multicore 4673 1325
BZip2 Compress 1100 421
BZip2 Compress Multicore 2136 772
BZip2 Decompress 1378 482
BZip2 Decompress Multicore 2727 938
JPEG Compress 1188 422
JPEG Compress Multicore 2359 816
JPEG Decompress 1613 436
JPEG Decompress Multicore 3121 845
PNG Compress 1368 453
PNG Compress Multicore 2797 889
PNG Decompress 1293 557
PNG Decompress Multicore 2565 1086
Sobel 1595 330
Sobel Multicore 3087 637
Lua 1365 395
Lua Multicore 2667 762
Dijkstra 1108 520
Dijkstra Multicore 1977 919

Floating Point Performance

iPad mini with Retina Display iPad mini
Floating Point 1331 225
Floating Point Multicore 2630 437
BlackScholes 1339 342
BlackScholes Multicore 2631 673
Mandelbrot 903 291
Mandelbrot Multicore 1789 563
Sharpen Filter 1147 229
Sharpen Filter Multicore 2280 438
Blur Filter 1310 220
Blur Filter Multicore 2602 429
SGEMM 1184 190
SGEMM Multicore 2319 346
DGEMM 1124 89
DGEMM Multicore 2188 175
SFFT 1493 191
SFFT Multicore 2963 381
DFFT 1602 219
DFFT Multicore 3155 435
N-Body 1552 290
N-Body Multicore 3088 565
Ray Trace 1952 334
Ray Trace Multicore 3880 635

Memory Performance

iPad mini with Retina Display iPad mini
Memory 1390 169
Memory Multicore 1664 240
Stream Copy 1992 238
Stream Copy Multicore 2253 296
Stream Scale 1250 145
Stream Scale Multicore 1507 247
Stream Add 1204 152
Stream Add Multicore 1481 215
Stream Triad 1247 156
Stream Triad Multicore 1528 214

You can find a copy of the full results on Geekbench's website.

]]>
http://www.dudas.co.uk/ipad-mini-with-retina-display/fdcd8557-2ab6-45b5-a032-d644bb67d235Tue, 12 Nov 2013 20:24:34 GMT
<![CDATA[Switching on Objects in Objective-C]]>Objective-C's switch statements only work on primitive types that are constant at compile time. However, many Objective-C APIs expect the developer to determine their behaviour based on identifiers passed in as NSString. This leads to many if ([identifier isEqualToSting:@"stringA"]) {...} else if ([identifier isEqual... blocks in code to deal with, for example, KVO or -prepareForSegue:sender:.

To deal with this, HCObjectSwitch adds a simple syntax that is very similar to the native switch statement. In order to avoid clashing with the native syntax, all keywords start with a capital letter.

HCObjectSwitch

Overview

A simple way to implement object based switch-like statements in Objective-C using blocks. Any object that conforms to NSCopying can be used to switched on.

Example

id inVariable = /* ... */;
__block id outVariable;

Switch (segue.identifier)
{
    Case (@"EmbedLoginViewController")
    {
        self.loginViewController = segue.destinationViewController;
        outVariable = @"Embed";

        FallThroughToDefault();
    }, // each case statement needs to be wrapped in parenthesees and terminated with a comma

    Case (@"ShowSettingsViewController")
    {
        HCSettingsViewController *settingsViewController = segue.destinationViewController;
        settingsViewController.delegate = self;
        settingsViewController.title = inVariable;

        outVariable = @"Show";

        FallThroughToDefault();
    },

    Default
    {
        // The _object_ object is the object that was used in the switch statement.
        // This is available automatically.
        NSLog(@"Segue '%@' triggered by: %@", _object_, sender);
    },
}; // The ; is required

Usage

The syntaxt for HCObjectSwitch is very close to the standard switch statement. All keywords start with a capital letter.

  • Switch (object) Starts a switch clause on object
  • Case (option) Code executed if the object matches option. This is implemented through blocks under the hood, thus when writing to variables in the enclosing scope they need to be __block.
  • Default Code executed in the default case
  • FallthroughTo(option) Fall through to the option case. Cases can be skipped.
  • FallThroughToDefault Fall through to the default case. Cases can be skipped.

Parentheses after the Switch and Case statements are required, as is the comma at the end of the parenthesis.

]]>
http://www.dudas.co.uk/switching-on-objects-in-objective-c/658dc0d1-7932-4884-9733-4ec52bf0cb2dSat, 09 Nov 2013 11:21:42 GMT