■基礎から学ぶ iPhoneアプリ開発
|
対象となるページ |
P.83●画像表示ビューを作成する |
iPhone 4では、iPhone 4用に最適化された画像を表示し、フィット表示で横位置にすると強制終了してしまう不具合が見つかりました(iPhone 4以外の、iOS 4をインストールした他のデバイスでは、この問題は発生しません。)。 この問題を回避するには、次のようにしてください(ソースコードについてはサンプルもご確認ください)。
P.83 ページ末尾のソースコードの中で、プロパティ「image」の定義に「noatomic」を追加します。
====
// 画像データのプロパティの定義 @property (retain, nonatomic) UIImage *image;====
P.86 ページ先頭のソースコードの「@end」の前に次のメソッドを追加します。
====
- (void)setImage:(UIImage *)newImage
{
// 同じ画像ではないかチェックする
if (newImage != _image)
{
// 古い画像を解放する
[_image release];
_image = nil;
if (newImage != nil)
{
// 新しい画像が大きいときは縮小するので
// サイズを調べる
CGSize imageSize = newImage.size;
if (imageSize.width > 1024 ||
imageSize.height > 1024)
{
// 1024*1024以下のサイズになるように
// 縦横比を維持したまま縮小する
CGSize newSize;
// 新しいサイズを計算する
// 幅と高さで長い方が1024になるようにする
// 小数点以下の値が出ないように、「int」型でキャストして
// 切り捨てを行っている
if (imageSize.width > imageSize.height)
{
newSize = CGSizeMake(1024,
(int)(imageSize.height * 1024 / imageSize.width));
}
else
{
newSize = CGSizeMake(
(int)(imageSize.width * 1024 / imageSize.height),
1024);
}
// 縮小準備
UIGraphicsBeginImageContext(newSize);
// 縮小描画
[newImage drawInRect:
CGRectMake(0, 0, newSize.width, newSize.height)];
// 画像取得
_image = UIGraphicsGetImageFromCurrentImageContext();
[_image retain];
// 縮小完了
UIGraphicsEndImageContext();
}
else
{
// このサイズの画像はそのまま使用する
_image = [newImage retain];
}
}
}
}
====
なお、プロジェクトにある本書のサンプル画像では、この問題は発生しません。また、同じ画像データでもフィット表示以外では問題は発生しません。
|
対象となるページ |
P.400●実機へのインストール |
P.400からP.402の中の「iPhone Program Portal」という表記は「iPhone Provisioning Portal」の誤りでした。お詫びして訂正させていただきます。
|
対象となるページ |
P.34●Objective-Cの基礎知識 |
「有効範囲」についてですが、誤解を与えてしまう可能性のある記述でした。お詫びして訂正させていただきます。
誤
★有効範囲
変数が宣言された場所によって、使用できる範囲が決まります。使用できる範囲は、変数が宣言されたスコープ内です。スコープは、「{」で始まり、「}」で閉じられる範囲です。
====
int x;
{
// ここでは変数「y」はまだ宣言されていないため使用できない
int y;
// ここでは変数「x」と変数「y」を使用できる
}
// ここでは変数「y」はスコープの外側のため、使用できない
// 変数「x」は使用できる
====
正
★有効範囲(スコープ)
変数は宣言された場所によって使用できる範囲が決まっています。使用できる範囲をスコープと呼び、「{」で始まり、「}」で閉じられる範囲をブロックスコープと呼びます。ブロックスコープ内で宣言された変数は、そのブロックスコープ内でのみ使用できます。関数やメソッドも一つのブロックスコープと見なすことができます。また、関数やメソッドの外側で宣言された変数は、宣言されたソースファイル内のどこからも使用できます。
====
int x;
{
// ここでは変数「y」はまだ宣言されていないため使用できない
int y;
// ここでは変数「x」と変数「y」を使用できる
}
// ここでは変数「y」は範囲外のため使用できない。変数「x」は使用できる
====|
対象となるページ |
P.287●画像付きテキストメモ機能を実装する |
「TextMemoViewController.m」のコードにメモリリークが見つかりました。「changeImage:」メソッドの最後(P.287の上から14行目)に、「[picker release];」を追加してください。お詫びして訂正させていただきます。
====
// 画像を変更する
- (IBAction)changeImage:(id)sender
{
// カメラが使用できないときは何もしない
if (![UIImagePickerController isSourceTypeAvailable:
UIImagePickerControllerSourceTypeCamera])
{
// 使用できない
return;
}
// イメージピッカーを作成する
UIImagePickerController *picker;
picker = [[UIImagePickerController alloc] init];
// イメージソースを設定する
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
// デリゲートを設定する
picker.delegate = self;
// イメージピッカーを表示する
[self presentModalViewController:picker
animated:YES];
[picker release];
}
====|
対象となるページ |
P.329●クイズを表示する |
「QuizViewController.m」のコードにメモリリークが見つかりました。メソッドの最後(コードの下から4行目)に、「[viewController release];」を追加してください。お詫びして訂正させていただきます。
====
#import "QuizViewController.h"
#import "QuizRunningViewController.h"
#import "Quiz.h"
@implementation QuizViewController
// 解放処理
- (void)dealloc
{
[_quiz release];
[super dealloc];
}
// クイズを開始するメソッド
- (IBAction)startQuiz:(id)sender
{
// クイズデータが読み込まれていないときは読み込む
if (!_quiz)
{
// インスタンス作成
_quiz = [[Quiz alloc] init];
// クイズデータのファイルパスを取得する
NSBundle *bundle = [NSBundle mainBundle];
NSString *path;
path = [bundle pathForResource:@"quiz"
ofType:@"txt"];
// ファイルから読み込む
[_quiz readFromFile:path];
}
// 2回目以降の場合があるので、出題済みの情報をクリアする
[_quiz clear];
// クイズ出題画面用のビューコントローラを取得する
QuizRunningViewController *viewController;
viewController = [[QuizRunningViewController alloc] init];
// クイズ情報を設定する
[viewController setQuiz:_quiz];
// クイズ出題画面を表示する
[self presentModalViewController:viewController
animated:YES];
[viewController release];
}
@end
====|
対象となるページ |
P.4●開発環境について |
SDKなどのバージョンアップに伴い、次の環境でも動作の検証を行い、問題なく動作することを確認しました。
・Mac OS X 10.6.4
・Xcode 3.2.4
・iOS SDK 4.1
・iOS 4.1
なお、ダウンロードできるサンプルコードはiOS SDK 4.0用になっていますので、それ以外のバージョンでは、次のような設定を行う必要があります。
■ユニバーサルアプリケーション(CHAPTER 02、CHAPTER 05)
(1) 「プロジェクト」メニューから「プロジェクト設定を編集」を選択します。プロジェクト設定ウインドウが表示されます。
(2) 「一般」タブをクリックします。
(3) 「すべての構成のベースSDK」からインストールされているデバイスSDKを選択します(たとえば、「iOS SDK 4.1」の場合は、「iOS デバイス 4.1」を選択します)。
(4) 「プロジェクト設定」ウインドウを閉じます。
(5) 「プロジェクト」メニューから「アクティブターゲット"ターゲット名"を編集」を選択します。ターゲット設定ウインドウが表示されます(ターゲット名は開いているプロジェクトのターゲット名が表示されます。たとえば、CHAPTER 02の場合は「HelloWorld」と表示されます)。
(6) 「ビルド」タブをクリックします。
(7) 「構成」から「すべての構成」が選択されていることを確認します。選択されていない場合は、選択してください。
(8) 「ベースSDK」から(3)で選択したデバイスSDKを選択します。
(9) ターゲット設定ウインドウを閉じます。
(10) プロジェクトファイルを閉じます。
(11) プロジェクトファイルを再度、開きます。
■ユニバーサルアプリケーション以外(CHAPTER 03、CHAPTER 04、CHAPTER 06)
(1) 「プロジェクト」メニューから「プロジェクト設定を編集」を選択します。プロジェクト設定ウインドウが表示されます。
(2) 「一般」タブをクリックします。
(3) 「すべての構成のベースSDK」からインストールされているデバイスSDKを選択します(たとえば、「iOS SDK 4.1」の場合は、「iOS デバイス 4.1」を選択します)。
(4) プロジェクト設定ウインドウを閉じます。
(5) プロジェクトファイルを閉じます。
(6) プロジェクトファイルを再度、開きます。
|
対象となるページ |
P.4●開発環境について |
iOS SDK4.2にアップデートされ、iPhone、iPad、iPod TouchのOSのバージョンがかわりました。次のサンプルプログラムの動作確認を行い、正しく動作することを確認しました。
・Mac OS X 10.6.5
・Xcode 3.2.5
・iOS SDK 4.2
・iOS 4.2.1
また、サンプルアプリケーションの動作環境および筆者の動作環境は、次のようになります。
===
本書で作成しているサンプルアプリケーションの動作環境は、次の通りです。
・iOS 4.0/4.1/4.2.1 (iPhone iPod touch)
・iOS 3.2/4.2.1 (iPad)
筆者の動作確認環境は、次の通りです。
・iPhone 3G (iOS 4.0)
・iPhone 3GS (iOS 4.0)
・iPhone 4 (iOS 4.0/4.1/4.2.1)
・iPod touch 3rd Generation (iOS 4.0/4.2.1)
・iPad WiFiモデル (iOS 3.2/4.2.1)
また、本書で作成しているサンプルアプリケーションの、それぞれの機種に対する動作環境は次のようになります。
| サンプル | iPad | iPhone/iPod touch |
| CHAPTER 02 | ◎ (Universal) | ◎ |
| CHAPTER 03 | ○ | ◎ |
| CHAPTER 04 | ○ | ◎ |
| CHAPTER 05 | ◎ (Universal) | ◎ |
| CHAPTER 06 | ○ | ◎ |
| CHAPTER 07 | ○ (iOS 4.2.1以降) | ◎ |
iPhone用として作成する、CHAPTER 03、CHAPTER 04、CHAPTER 06のサンプルアプリケーションをiPad上で動作させるには、iOS SDK
4.2以降を使用してください。iOS SDK 4.2未満の場合には、ベースSDKのバージョンを「3.2」に変更してください。設定の変更は、プロジェクト設定などから行います。
CHAPTER 07のサンプルアプリケーションはiOS 4.0の機能を使用していますので、iOS 4.0未満の環境では動作しません。iPadでCHAPTER 07のサンプルアプリケーションを実行するには、iOS 4.2.1以降をインストールし、iOS SDK
4.2以降を使用してください。
===
なお、ダウンロードできるサンプルコードはiOS SDK 4.0用になっていますので、それ以外のバージョンでは、【その6】と同様に、設定を行う必要があります(ベースSDKは、「iOS 4.2」もしくは「Latest iOS(currently set to iOS 4.2)」を選択してください)。
|
対象となるページ |
P.98●イメージピッカーに対応する |
「openImage」メソッドのコードに誤りがありました。「openImage」メソッドの7行目を次のように修正してください。お詫びして訂正させていただきます。
誤
====
NSString *photoLibraryStr = NSLocalizedString(kPhotoLibrary, "");====
正(@を追加してください)
====
NSString *photoLibraryStr = NSLocalizedString(kPhotoLibrary, @"");====
|
対象となるページ |
P.100-101●イメージピッカーに対応する |
「ImageViewerViewController.m」のコードに誤りがありました。「actionSheet:clickedButtonAtIndex:」メソッドの最後に、「[picker release];」を追加してください。お詫びして訂正させていただきます。
====
- (void)actionSheet:(UIActionSheet *)actionSheet
clickedButtonAtIndex:(NSInteger)buttonIndex
{
// ボタンのインデックス番号が0のときは、キャンセルボタン
if (buttonIndex > 0)
{
picker = [[UIImagePickerController alloc] init];
// イメージソースを設定する
picker.sourceType =
UIImagePickerControllerSourceTypePhotoLibrary;
// デリゲートを設定する
picker.delegate = self;
// イメージピッカーを表示する
[self presentModalViewController:picker
animated:YES];
[picker release]; // この行を追加
}
}
====|
対象となるページ |
P.100-101●イメージピッカーに対応する |
「ImageViewerViewController.m」のコードに誤りがありました。「actionSheet:clickedButtonAtIndex:」メソッドの最後に、「[picker release];」を追加してください。お詫びして訂正させていただきます。
====
- (void)actionSheet:(UIActionSheet *)actionSheet
clickedButtonAtIndex:(NSInteger)buttonIndex
{
// ボタンのインデックス番号が0のときは、キャンセルボタン
if (buttonIndex > 0)
{
picker = [[UIImagePickerController alloc] init];
// イメージソースを設定する
picker.sourceType =
UIImagePickerControllerSourceTypePhotoLibrary;
// デリゲートを設定する
picker.delegate = self;
// イメージピッカーを表示する
[self presentModalViewController:picker
animated:YES];
[picker release]; // この行を追加
}
}
====|
対象となるページ |
P.222●場所のメモ機能を実装する |
「RootViewController.m」ファイルのコードに不要なコメントがありました。p.222の上から8行目の下記のコメントです。お詫びして訂正いたします。
====
// 変更したときに値がずれないようにするため====
|
対象となるページ |
P.225●場所のメモ機能を実装する |
「LocationMemoViewController.h」ファイルのコードにコメント誤りがありました。お詫びして訂正いたします。
誤
====
// 経度を表示するラベル UILabel *_latitudeLabel; // 経度を表示するラベル UILable *_longitudeLabel;====
正(最初の「経度」は「緯度」の誤りです)
====
// 緯度を表示するラベル UILabel *_latitudeLabel; // 経度を表示するラベル UILabel *_longitudeLabel;====
|
対象となるページ |
P.86●画像表示ビューを作成する |
ソースコードの一部に間違いがありました(アプリの動作は問題ありませんが、コメントと食い違っていました)。お詫びして訂正させていただきます。
誤
====
// 新しいサイズを計算する
// 幅と高さで長い方が1024になるようにする
// 小数点以下の値が出ないように、「int」型でキャストして切り捨てを行っている
if (imageSize.width > imageSize.height)
{
newSize = CGSizeMake(1024,
(int)imageSize.height * 1024 / imageSize.width);
}
else
{
newSize = CGSizeMake((int)imageSize.width * 1024 / imageSize.height,
1024);
}
====正(「(int)」の後ろと行末に括弧を追加)
====
// 新しいサイズを計算する
// 幅と高さで長い方が1024になるようにする
// 小数点以下の値が出ないように、「int」型でキャストして切り捨てを行っている
if (imageSize.width > imageSize.height)
{
newSize = CGSizeMake(1024,
(int)(imageSize.height * 1024 / imageSize.width));
}
else
{
newSize = CGSizeMake((int)(imageSize.width * 1024 / imageSize.height),
1024);
}
====