2011年6月4日土曜日

NSURLConnectionによる非同期通信での注意

2時間くらいハマったのでメモ。
NSURLConnectionで非同期通信をする際、

[NSURLConnection connectionWithRequest:delegate:]

などを呼ぶスレッドがメインスレッドはない場合、
デリゲートへの一切のメッセージ送信が行われないようです。

別スレッドからロードを開始する場合は、

[NSURLConnection sendSynchronousRequest:returningResponse:error:]

あたりを使って意図的に同期通信にしないとダメですね。

2011年6月1日水曜日

getterのブラケット記法をドットに置き換える方法

注意:
ドット記法が使えないgetterの多くは、何らかの意図があってドット記法を許さないようにしていると推測できます。
乱用は控えましょう。


Objective-Cでは、ヘッダで @property を用いてアクセサを定義した場合のみ
メソッドをドット記法で呼び出すことができます。
(該当メソッドが存在すれば呼ぶことはできますが、警告が出るはずです。)

また、Objective-Cでは、カテゴリを用いて既存のオブジェクトを拡張することができます。

この二つの機能を用いて、
ドット記法で呼び出せないはずのインスタンスメソッド
をドット記法で呼び出せるようにできます。

やり方:

//
//  NSString+dotOperator.h
//  M2
//

@interface NSString (dotOperator)

@property (readonly) NSUInteger length;

@end


//
//  NSString+dotOperator.m
//  M2
//

#import "NSString+dotOperator.h"

@implementation NSString (dotOperator)

@dynamic length;

@end



上記の例では、

- [NSString length]

をドット記法で呼び出せるようにしました。
この拡張を使いたいファイル(もしくは***.pch)で

#import "NSString+dotOperator.h"

とすることで、下記のような書き方が可能になります。

NSLog(@"%d", @"abc".length);


括弧の入れ子が少なくなって便利ですが、使いどころを考えないとハマる可能性はありますよね!

NSStringをLL風に置換・加工できるようにするカテゴリ拡張

参考: getterのブラケット記法をドットに置き換える方法

@"abc".replace(@"b", @"d"); // adc
@"abc".append(@"def");      // abcdef
@"abc".length;              // 3

のような形で、文字列を扱えるようになるカテゴリです。
ブロックを得るgetterを設定していますが、関数の中身まではXcodeで補完できないので、
引数の数などにご注意下さい。
(引数チェックは省いています。)

//
//  NSString+LLLikeOperation.h
//  M2
//

typedef NSString *(^NSStringReplacer)(NSString *existingString, NSString *newString);
typedef NSString *(^NSStringAppender)(NSString *aString);

@interface NSString (LLLikeOperation)

@property (readonly) NSUInteger length;
@property (readonly) NSStringReplacer replace;
@property (readonly) NSStringAppender append;

@end



//
//  NSString+LLLikeOperation.m
//  M2
//

#import "NSString+LLLikeOperation.h"

@implementation NSString (LLLikeOperation)

@dynamic length;

- (NSStringReplacer)replace
{
  NSStringReplacer replacer = ^NSString*(NSString *existingString, NSString *newString) {
    return [self stringByReplacingOccurrencesOfString:existingString withString:newString];
  };
  
  return replacer;
}

- (NSStringAppender)append
{
  NSStringAppender appender = ^NSString*(NSString *aString) {
    return [self stringByAppendingString:aString];
  };
  
  return appender;
}

@end