Category Archives: Objective-C

IBOutlet接続オブジェクトの初期化

0
Filed under iOS SDK, Objective-C
Tagged as ,

難解なイントロ

説明が難しいのですが、Xcode4のリソースエディタ(旧Interface Builder)で配置したオブジェクトをまとめたUIViewを、オリジナルUIViewの派生クラスインスタンスとして設定した場合、その初期化について、どういうメソッドがどういうタイミングで呼ばれるのか分からなかったので調べてみることにしました。
うーん、分かりにくいですね。
簡単な説明にトライしてみます!

分かりやすいイントロ

リソースはほとんどプログラムでも生成できるのですが、やっぱりリソースエディタで配置したほうがやりやすいものとかあります。
そういうものをまとめたUIViewについて、たとえばButtonsとかいう独自クラスをつくってみたりすることがあります。

1
2
3
4
5
6
@interface Buttons : UIView{
  IBOutlet UILabel*  label;
  IBOutlet UIButton* bt1;
  IBOutlet UIButton* bt2;
  IBOutlet UIButton* bt3;
}

で、それをリソースエディタで配置したリソースに接続したとします。

1
2
3
@interface ButtonsContainer : UIView{
  IBOutlet Buttons* buttons;
}

で、Buttonsのクラスの初期化をしたい場合、どこのメソッドで描くべきなのか?ということなのです。

初期化の流れ

いきなり結論ですが、初期化メソッドは、
- (id) initWithCoder:(NSCoder*)aDecoder;
が、呼ばれ、その後に、
- (void)awakeFromNib;
が呼ばれます。
ちなみに、setFrameも呼ばれるので、そこに挿し込むのもいいかもしれません。
initメソッドや、initWithFrameは呼ばれないので注意が必要です。

初期化関連メソッドの呼ばれる順番

initWithCoderは次のような実装になると思います。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@implementation Buttons
 
- (id) initWithCoder:(NSCoder*)aDecoder{
  if( (self=[super initWithCoder:aDecoder]) ){
    // 初期化.
    NSLog(@"2");
  }
  return self;
}
 
- (void)setFrame:(CGRect)frame{
  [super setFrame:frame];
  NSLog(@"1");
}
 
- (void)awakeFromNib{
  NSLog(@"3");
}
 
@end

setFrameは、[super initWithCoder:]から呼ばれるので最初に呼ばれるのです。
基本的な初期化が終わったら、awakeFromNibが呼ばれる、という順番ですね。
上記コードに挿入してあるNSLogはその数字を順番に出力するはずです。

考察

initではなく、initWithFrameでもなく、initWithCoderが呼ばれるので、シリアライズされているリソースがデシリアライズされていることが分かります。
今まで、(Interface Builderなどの)リソースエディタで作られたリソースをどうやって保持しているか疑問だったのですが、これでいろいろ解決しました。
ちなみに、awakeFromNibは、NSObjectにカテゴリで追加されている機能なので、普通にリファレンスを見ていても出てきません。


[AD]

↓エンジニア的読み物として今一番読みたい一冊。

エンジニアとしての生き方  IT技術者たちよ、世界へ出よう! (インプレス選書)

著者/訳者:中島 聡

出版社:インプレスジャパン( 2011-03-11 )

定価:¥ 1,680

Amazon価格:¥ 1,680

単行本(ソフトカバー) ( 272 ページ )

ISBN-10 : 4844329944

ISBN-13 : 9784844329947


↓これは良書の予感!アルゴリズムをリファレンスとしてまとめるというのがいい!

アルゴリズムクイックリファレンス

著者/訳者:George T. Heineman Gary Pollice Stanley Selkow

出版社:オライリージャパン( 2010-04-26 )

定価:¥ 3,360

Amazon価格:¥ 3,360

単行本(ソフトカバー) ( 396 ページ )

ISBN-10 : 4873114284

ISBN-13 : 9784873114286


↓上記アルゴリズムクイックリファレンスを見て連想したのはこの名著。もちろん私も持っていますし、プログラマは必携です!

C言語による最新アルゴリズム事典 (ソフトウェアテクノロジー)

著者/訳者:奥村 晴彦

出版社:技術評論社( 1991-03 )

定価:¥ 2,447

Amazon価格:¥ 2,447

単行本 ( 443 ページ )

ISBN-10 : 4874084141

ISBN-13 : 9784874084144


↓iPad2を使い始めているのですが、こういうスタンドは欲しくなりますね!机の上に置いておくより絶対良さそう。しかもこれはスタンド自身が収納性に優れている!

デバイスジャパン Apple iPad対応スタンド(Xstand)

デバイスジャパン Apple iPad対応スタンド(Xstand)

定価:¥ 3,980

Amazon価格:¥ 1,100

カテゴリ:エレクトロニクス


↓iPad2に手で書いていると段々限界が見えてくる。やっぱりペンが欲しい!

プリンストンテクノロジー iPad/iPhone/iPod touch専用タッチペン (ブラック) PIP-TP2B

プリンストンテクノロジー iPad/iPhone/iPod touch専用タッチペン (ブラック) PIP-TP2B

定価:¥ 1,580

Amazon価格:¥ 798

カテゴリ:エレクトロニクス

発売日:2010-07-10


NSMutableArrayのNULL初期化

0
Filed under iOS SDK, Objective-C
Tagged as , ,

ちょっとNSMutableArrayの使い方でハマったのでメモです。
box cube empty clear glassphoto © 2008 Simon | more info (via: Wylio)

やりたいこと:配列をヌルで埋めたい

  • 大量のオブジェクトを管理したい
  • その個数は決まっているので固定長で確保しておきたい
  • まずnilで埋めておき、後で任意のインデックスのオブジェクトを置き換えたい

という意図で次のようなコードを書くとエラーになります。

1
2
3
4
NSMutableArray* array = [NSMutableArray arrayWithCapacity:numMax];
for( int i=0; i<numMax; i++ ){
  [array addObject:nil];
}

次のコードも無理です。

1
2
3
4
NSMutableArray* array = [NSMutableArray arrayWithCapacity:numMax];
for( int i=0; i<numMax; i++ ){
  [array replaceObjectAtIndex:i withObject:nil];
}

これは、NSMutableArrayはnilを要素として受けつけないからです。
さぁどうしよう、と思って調べてみたらいつものQ&Aサイト:StackOverFlowにまさにそんな意図の質問がありました!

NSNull

で、解決方法は、NSNullというクラスのオブジェクトを作る、ということでした。

具体的なコードは次のようになります。

1
2
3
4
NSMutableArray* array = [NSMutableArray arrayWithCapacity:numMax];
for( int i=0; i<numMax; i++ ){
  [array addObject:[NSNull null]];
}

これならオブジェクトを配置できて、しかも後からNULL判定できます。
ちなみに判定コードは次のようになります。

1
2
3
4
NSNull* nullValue = [NSNull null];
if( [array objectAtIndex:index] == nullValue ){
  NSLog(@"This is null!!");
}

もちろん、NSNullのオブジェクトが入っているので、nilとの比較では判定できません。


[AD]

↓タイトルからは予想できないが、XML解析、OAuth認証、Core Dataを使ったサンプルなど意外に良書の予感!

つくって覚えるObjective-C入門 iOS対応

著者/訳者:オフィス加減

出版社:アスキー・メディアワークス( 2011-03-10 )

定価:¥ 1,890

Amazon価格:¥ 1,890

単行本(ソフトカバー) ( 272 ページ )

ISBN-10 : 4048703641

ISBN-13 : 9784048703642


↓こないだ買いました!Titanium、Facebookアプリなど、なかなかおもしろい話題が多く、これはお買い得!

WEB+DB PRESS Vol.61

著者/訳者:西岡 祐弥 濱田 章吾 浦嶌 啓太 高橋 健一 柴田 博志 井上 誠一郎 大谷 弘喜 荻野 淳也 原 悠 増井 俊之 横山 彰子 浜本 階生 ミック uupaa 塙 与志夫 はまちや2 大沢 和宏 中島 聡 矢野 りん 中島 拓

出版社:技術評論社( 2011-02-24 )

定価:¥ 1,554

大型本 ( 200 ページ )

ISBN-10 : 4774145440

ISBN-13 : 9784774145440


↓とうとう出た!「まんが日本昔ばなし」のDVD BOX!!第1集は、「桃太郎」「カチカチ山」など全20話

まんが日本昔ばなし DVD-BOX 第1集(5枚組)

販売元:東宝( 2011-04-01 )

定価:¥ 14,700 ( 中古価格 ¥ 10,490 より )

Amazon価格:¥ 10,940

時間:225 分

5 枚組 ( DVD )


Objective-Cの既存のクラスを拡張する仕組み

0
Filed under iPhone, Objective-C, プログラミング言語
Tagged as , , , , ,

Objective-Cには「カテゴリ」という機能があり、それについて調べたときのメモをまとめました。

その名は「カテゴリ」

ネットに転がっているソースを見ていて、それまで見たことなかった書き方があったときにはそれをどうやって調べたらいいのか、なかなか手こずります。その書き方そのものの名を知らないからです。
今回の例で言うと「カテゴリ」という機能のことで、下記のような感じで書かれていたら、それはカテゴリ機能を使っているのです。

1
@inteface NSString (HogeHoge)

このカテゴリ機能を活用すると、既存のクラスをちょっと機能拡張したい時に無駄なクラスを作る必要がなくなります。
例えば、文字列を扱うクラス NSString をに機能を追加したいことはよくあるのですが、NSStringの中身に応じたハッシュ値(MD5)を出力できるようなメソッドを追加する、という例に説明してみます。
MD5の機能実装の参考にしたのはこちらのサイト。関数の中身は全く同じです。

ざっくりしたカテゴリの書き方と使い方

まず、カテゴリ定義の書き方。
NSStringにMD5の機能を追加する場合、ファイル名は、NSString+MD5.h, NSString+MD5.m とするのがマナーのようです。
また、後述するソースを見ると分かるのですが、定義部は @inteface NSString (MD5)、実装部は @implementation NSString (MD5) という感じにして、あとは通常のクラス定義と同じように書きます。
次に使い方ですが、#import “NSString+MD5.h” として一緒にビルドすれば、そのソース内でNSStringインスタンスは全てMD5カテゴリの機能を持つことが出来ますので、下記のようなコードでMD5値を出力させることが出来ます。

1
2
NSString* strTest = @"テスト文字列";
NSLog( @"original[%@], MD5[%@]", strTest, [strTest MD5String] );

NSString+MD5 コード全容

1
2
3
4
5
6
7
//  NSString+MD5.h
 
#import <Foundation/Foundation.h>
 
@interface NSString (MD5)
- (NSString*) MD5String;
@end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//  NSString+MD5.m
 
#import "NSString+MD5.h"
#import <CommonCrypto/CommonDigest.h> // for CC_MD5
 
@implementation NSString (MD5)
- (NSString *) MD5String
{
  const char *cStr = [self UTF8String];
  unsigned char result[CC_MD5_DIGEST_LENGTH];
  CC_MD5( cStr, strlen(cStr), result );
  return [NSString stringWithFormat:
    @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
    result[0], result[1], result[2], result[3], 
    result[4], result[5], result[6], result[7],
    result[8], result[9], result[10], result[11],
    result[12], result[13], result[14], result[15]
    ];  
}
@end

iOS SDKのMD5関数についての説明

おまけとして、上記のソースの内容を説明します。
MD5への変換関数 CC_MD5はiOS SDKにC言語ライブラリが用意されています。(リファレンスはこちら

CC_MD5は、次のように定義されています。

1
2
extern unsigned char*
CC_MD5(const void *data, CC_LONG len, unsigned char *md);

data が元になるデータのポインタ。
len がdataの長さ。
md がMD5計算の結果を格納する出力用バッファへのポインタで、CC_MD5_DIGEST_LENGTHの長さが必要なので、予め用意しておきます。本当はCC_MD5_DIGEST_LENGTHの長さに合わせて、出力部分を対応できるよう書いておく必要がありますが、CC_MD5_DIGEST_LENGTHは、そうそう16から変わることはないので、出力部分を固定で16要素並べてstringWithFormatで出力させています。

クラスの機能分割、という視点

カテゴリについての詳しい説明は、「Dynamic Objective-C」という書籍にも3ページに渡って説明されているのですが、こちらでの視点はチョット違う。

Dynamic Objective-C

著者/訳者:木下 誠

出版社:ビー・エヌ・エヌ新社( 2009-03-27 )

定価:¥ 3,360

Amazon価格:¥ 3,360

単行本 ( 456 ページ )

ISBN-10 : 4861006414

ISBN-13 : 9784861006418


そのセクション名は「カテゴリ ―動的なメソッドの追加によるクラスの拡張」となっていながらも、最初の段落の説明は次にように書かれている。

Objective-Cには、カテゴリと呼ばれる機能がある。クラスが持つメソッドを、名前の通りカテゴリごとに分類するための機能だ。これを使うことで、大きなクラスでもコーディングしやすいように分割することができる。

そもそもカテゴリとは、クラス実装を分割するための仕組み、だというのだ。
なるほど、そう考えるとカテゴリが「カテゴリ」という名前の由来もわかるし、ウェブに転がるサンプルのファイル名がHOGEHOGE-FOO.hとかハイフン繋ぎになっているモノがあるのも理解できる。
MVCモデルでクラスを分けても大きくなってしまうクラスはあるし、その場合にはカテゴリを使った機能分割も視野に入れていいかもしれない。
その他にもObjective-Cの深いところをじっくり説明してくれている「Dynamic Objective-C」はおすすめ書籍です!

カテゴリで出来ないこと

後から知ったのですが、カテゴリ機能で「クラスのインスタンス変数の追加」は出来ないようですね。
これ、結構重要なポイントだと思います。

参考サイト:『kuro’s blog : Objective-C:カテゴリで「できること」と「できないこと」』


[AD]

↓「CHAPTER09 カテゴリ」とカテゴリについて章を割いて説明されているようです!

詳解 Objective-C 2.0 改訂版

著者/訳者:荻原 剛志

出版社:ソフトバンククリエイティブ( 2010-12-17 )

定価:¥ 3,990

Amazon価格:¥ 3,990

大型本 ( 608 ページ )

ISBN-10 : 4797361786

ISBN-13 : 9784797361780


↓昨年8月に亡くなった今敏が1985年〜1986年に連載していたマンガ!面白そう!

OPUS(オーパス)上(リュウコミックス) [コミック]

著者/訳者:今 敏

出版社:徳間書店( 2010-12-13 )

定価:¥ 980

Amazon価格:¥ 980

コミック ( ページ )

ISBN-10 : 4199502211

ISBN-13 : 9784199502217


↓PS3もXbox360も持っていないけど、これは面白そう!

キャサリン 特典 サントラCD付き

キャサリン 特典 サントラCD付き

定価:¥ 7,329

Amazon価格:¥ 4,860

カテゴリ:Video Game

発売日:2011-02-17


Objective-Cで頭を悩ませる

2
Filed under Objective-C
Tagged as , ,

今回のエントリは、ここ数週間、Objective-CでiPhoneアプリ向けにコードをバリバリ書いているのですが、言語的に微妙に使い勝手が悪く、違和感を感じていたのですが、その原因の一つが分かった、という話です。
違和感の原因は、オブジェクト管理(メモリ的な意味)の分かりにくさ、でした。
私はC/C++での開発経験はあるので、ポインタが分からない〜、とかそういう話ではありません。(かつて、そういう時代もありましたがw)

retainしてんの?してないの?

retain/releaseという参照カウンタの仕組みは良いとは思うのですが、それ(retain)が全てではない、というところに問題の根源があると思うのです。
Counterphoto © 2008 Marcin Wichary | more info (via: Wylio)
copyするかもしれないし、assignかもしれない、という可能性を考えていたら、標準ライブラリの情報不足がジワリジワリと効いてきて、コードを書いてるのか、パズルを解いているのか分からなくなってきます。
例を上げてみます。
可変長の配列クラス NSMutableArray に addObject というメソッドがあります。
- (void)addObject:(id)anObject;
で、このメソッドが与えたオブジェクトをどう管理してくれているのか、それを知るすべが見つからないのです。
典型的な使用例として、下記のコードを見てください。このコードで問題ない、と言い切れるにはどれくらいの知識が必要でしょうか。

1
2
3
4
5
NSMutableArray* array = [[NSMutableArray alloc] init]; // (1)
NSObject* obj = [[NSObject alloc] init]; // (2)
[array addObject:obj]; // (3)
[obj release]; // (4)
[array release]; // (5)

(3)で渡したオブジェクトはretain/assign/copyの3通りの処理の可能性があります。
また、(5)のrelease時に、そのオブジェクトをどう処理しているか(releaseするのか、しないのか)を考える必要があります。
(3)で引数に渡したオブジェクトをretain、もしくはcopyしていたら、まぁ、(5)内では、オブジェクトをreleaseしてくれているとは想定できます。それをしないとほぼ確実にメモリリークしますしね。
しかし、(3)の引数処理がassign(参照渡しのみ)だったら、どうでしょうか?配列は破棄処理をするべきでしょうか。外部の使用者から見たら全く想像がつきませんね。
リファレンスにも次のようなことしか書いていませんでした。

addObject:
Inserts a given object at the end of the array.
- (void)addObject:(id)anObject
Parameters
anObject
The object to add to the end of the array’s content. This value must not be nil.
Important: Raises an NSInvalidArgumentException if anObject is nil.

anObjectはnilじゃだめだよ。nil渡したら例外投げるよ、ってことしか書かれていません。うーん、そうじゃなくて、引数を内部ではどう処理するのか、とかそういう情報も欲しいと思うんです。
結局下記のコードで、retainしていて、上記のコードで問題ないことを確認しました。

1
2
3
4
5
6
7
8
9
NSMutableArray *array = [[NSMutableArray alloc] init];
NSObject *obj = [[NSObject alloc] init];
NSLog(@" check A [%d]", (int)[obj retainCount]);	// 1
[array addObject:obj];
NSLog(@" check B [%d]", (int)[obj retainCount]);	// 2
[obj release];
NSLog(@" check C [%d]", (int)[obj retainCount]);	// 1
[array release];
NSLog(@" check D [%d]", (int)[obj retainCount]); // objがnilなので落ちる.

Open your mind!

retainも便利だとは思うし、積極的に使うべきだとは思うけど、明示して欲しいのですよ。
例えば、プロパティみたいに次のような構文が書けて、ヘッダーのメソッド宣言で分かればいいかも。
- (void)addObject:(id,retain)anObject;
あー、これだったらすっきりする!と自画自賛!!
特に標準じゃないライブラリとか、自分で書いたものとかですら、あとから使うときに困ることが多いんじゃないかな、と思うのですが、私だけでしょうか。


[AD]
↓「Chapter 3 オブジェクトの基本操作」が気になる

XcodeによるObjective-C入門

著者/訳者:大津 真

出版社:毎日コミュニケーションズ( 2010-01-23 )

定価:¥ 3,150

Amazon価格:¥ 3,150

単行本(ソフトカバー) ( 304 ページ )

ISBN-10 : 4839931879

ISBN-13 : 9784839931872



↓この本で言語仕様をしっかり勉強すべきかも。「CAPTER13:オブジェクトのコピーと保存」が上記エントリと関係ありそうですね。

詳解 Objective-C 2.0

著者/訳者:荻原 剛志

出版社:ソフトバンククリエイティブ( 2008-05-28 )

定価:¥ 4,410

大型本 ( 560 ページ )

ISBN-10 : 4797346809

ISBN-13 : 9784797346800