Control Fun(5)~Sample Code

2010. 08. 17
先に述べていましたが、手元にある旧版の『はじめてのiPhoneプログラミング』の内容と、新版『はじめてのiPhone3プログラミング』の内容と思しきApress社のサイト内のサンプルコードではいくつかの相違点がありますので、その辺の解説をしてみたいと思います。


●外観上のインターフェイスの違い

旧版のコードを説明通りに作ると、『Control Fun(1)~Image ViewとText Field』から『Control Fun(4)~Action SheetとAlert』で説明してきたものになります。

687

一方、新版の内容と思われるApress社のサイト内のサンプルコードは下図のようになっています。

688

中央付近のセグメンテッドコントロールが『Show/Hidden』から『Switches/Button』に変更され、Switchesの場合は2つの連動するスイッチが、Buttonの場合はDo Somethingボタンが表示されるように変更され、起動時にはDo Somethingボタンが表示されないようになっています。

689

見た目上は、表示の切り替え方式が変更されただけで、スイッチやDo Somethingボタンの機能に違いはありません。


●nibファイルの違い

外見上はスイッチが乗っていたswitchViewをDo Somethingボタン用にもう一枚作って切り替えているように見えるのですが、Control_FunViewController.xibを見るとそうではないことが分かります。

690

旧版では親ビュー下にスイッチを乗せるサブビューがあり、その下に二組のラベルとスイッチが置かれています。

691

しかし新版ではサブビューが無く、スイッチとDo Somethingボタンが直接置かれています。

更にキーボードを片付けるための隠しボタンが無く、親ビューがUIViewオブジェクトからUIControlオブジェクトに変更されています。


・隠しボタンの置換

UIViewとUIControlは以下のような関係になっています。

NSObject
    |
    ∟UIResponder
            |
            ∟UIView
                    |
                    ∟UIImageView
                    |
                    ∟UIControl
                            ∟UIButton
                            ∟UISegmentedControl
                            ∟UISlider

UIViewはUIControlのスーパークラスなのでUIViewの機能を継承しており、且つUIControlはUIButtonのスーパークラスなので、UIViewとUIControlを置換できるというわけです。

何故置換したかというとUIViewにはアクションを設定できないからで、DocumentウィンドウでUIViewを選択してInspectorウィンドウのConnectionsタブを開くと分かります。

692

UIViewのConnectionsタブにはアウトレットしか表示されません。

693

しかしUIControlのConnectionsタブにはアウトレットの他にEventsの項目があり、アクションを設定できるようになっています。

そして隠しボタンで呼び出していたメソッド『backgroundClick:』は『backgroundTap:』と名前を変え、隠しボタン同様『Touch Up Inside』で設定されています。
(backgroundClick:とbackgroundTap:メソッドの内容は同一です)

このようにするには、まずDocumentウィンドウで隠しボタン(親Viewのすぐ下にあるCustim Button)をEditメニューのDeleteで削除します。
(このボタンを削除しないと親Viewより前面にあるために入力を受け付けてしまい、親Viewが応答できない)

次にDocumentウィンドウで親Viewを選択し、InspectorウィンドウのIdentityタブで『Class Identity』の『Class』を『UIControl』に変更します。

694

そしてDocumentウィンドウでFirst Responderを選択し、InspectorウィンドウのConnectionsタブでbackgroundClick:をControl(旧親View)に接続します。

695

サンプルコードではFirst Responderと接続していますが、File's Ownerから接続しても動作します。
(サンプルコードが何故First Responderから接続しているのか、File's Ownerから接続するのとどう違うのかは分かりません)


・セグメンテッドコントロールの修正

nibファイル上でのセグメンテッドコントロールの違いは少なく、Attributesタブで言えばTitleが『Show/Hide』から『Switches/Button』になっているくらいです。

そしてConnectionsタブを見ると、toggleShowHide:メソッドからtoggleControls:メソッドに変わっています。

両メソッドは中身が異なりますので後述しますが、ここではそのままにしておきます。
(メソッド名を変えると接続し直さなければならないので)


・スイッチの変更

サンプルコードでは、スイッチのラベルが無く、サブビューも使用していません。

最小限の変更で動作確認を済ませたいので、まずDocumentウィンドウでスイッチ二つをドラッグ&ドロップでサブビューから外します。

696

そしてサブビューを選択し、InspectorウィンドウのAttributesタブで、『View』の『Drawing』で『Hidden』にチェックを入れます。

697

この状態ですと、サブビューの後面にスイッチがある状態ですが、サブビューをHiddenにすることで無効にできますので、(後で元に戻す手間などを考えると)動作確認する分にはこれで構わないと思います。

また、起動時にDo Somethingボタンを非表示にしたいので、InspectorウィンドウのAttributesタブで、『View』の『Drawing』で『Hidden』にチェックを入れます。

698

Do Somethingボタンはスイッチと同じような位置にありますが、動作確認するだけですのでそのままの位置に置いておきます。


●ヘッダファイルの違い

サブビューを使用しないため、switchViewアウトレットとプロパティが不要になります。

キーボードを片付けるメソッド名がbackgroundClick:からbackgroundTap:になっていますが、前述の通り中身は一緒です。
(リファレンス類を読んでると、『タップする』ところが『クリックする』になっていることがよくありますし)

アクションシートを表示するメソッド名がdoSomething:からbuttonPressed:になっていますが、これも中身は一緒です。

セグメンテッドコントロールのメソッド名がtoggleShowHide:がtoggleControls:になっていて中身が違うのですが、再接続の手間を考えてメソッド名はそのままにし、中身だけ書き換えます。

それとセグメンテッドコントロールの判定に使う定数名も、kShowSegmentIndexからkSwitchesSegmentIndexに変わっていますが、使用方法は変わらないのでそのままにします。

また、通常インスタンス変数の宣言で『IBOutlet ~』と記述することが多いのですが、新版サンプルコードではプロパティの宣言で『IBOutlet ~』と記述しています。

新版ではこの辺の説明がされているのかもしれませんが、私の手元に無いので違いが分かりません。


●ソースファイルの違い

・セグメンテッドコントロールのメソッド

まずセグメンテッドコントロールのメソッドから見てみます。

旧版のtoggleShowHide:は、スイッチの乗っているビューの表示/非表示を切り替えていましたが、新版のサンプルコードのtoggleControls:ではスイッチおよびDo Somethingボタンをhiddenプロパティで直接表示/非表示の切り替えを行っています。

また細かいところでは、引数senderをUISegmentedControlクラスにキャストして、selectedSegmentIndexプロパティでNSIntegerの変数segmentに代入していた部分が、引数senderからselectedSegmentIndexプロパティで値を得てそのまま比較に使用するよう、簡略化が図られています。

- (IBAction)toggleShowHide:(id)sender {
/*
    UISegmentedControl *segmentedControl = (UISegmentedControl *)sender;
    NSInteger segment = segmentedControl.selectedSegmentIndex;

    if (segment == kShowSegmentIndex) [switchView setHidden:NO];
    else [switchView setHidden:YES];
*/

    if ([sender selectedSegmentIndex] == kShowSegmentIndex) {
        leftSwitch.hidden = NO;
        rightSwitch.hidden = NO;
        doSomethingButton.hidden = YES;
    }
    else {
        leftSwitch.hidden = YES;
        rightSwitch.hidden = YES;
        doSomethingButton.hidden = NO;
    }
}

699

hiddenプロパティはUIViewクラスのものです。
(『スライドショーのフルスクリーン化(2)』を参照してください)

700

701


・viewDidUnloadとdealloc

旧版の本書内では説明されていませんが、新版のサンプルコードではアウトレットに対してviewDidUnloadでの所有権の放棄とdeallocでの解放を行っています。
(太字が追加した部分)

- (void)viewDidUnload {
    self.nameField = nil;
    self.numberField = nil;
    self.sliderLabel = nil;
    self.leftSwitch = nil;
    self.rightSwitch = nil;
    self.switchView = nil;
    self.doSomethingButton = nil;
    [super viewDidUnload];
}

- (void)dealloc {
    [nameField release];
    [numberField release];
    [sliderLabel release];
    [leftSwitch release];
    [rightSwitch release];
    [switchView release];
    [doSomethingButton release];
    [super dealloc];
}

702

この辺は説明が無くても定型文として書くものと考えた方が良さそうです。
(viewDidUnloadメソッドについては『Button Fun』を参照してください)


・dealloc
(NSObjectクラス)

- (void)dealloc

レシーバにより占有されているメモリを解放します。

(解放されたメモリがまだ再使用されていない場合)解放されたオブジェクトにメッセージが送信されると、後のメッセージはエラーと示されて生成されレシーバに送られます。

deallocメッセージは決して直接送信しないでください。

代わりにNSObjectプロトコルのreleaseメソッドを通して、オブジェクトのdeallocメソッドを間接的に呼び出すことができます。
(releaseメッセージを送信した結果、レシーバのretainカウントが0になれば解放します)

これらのメソッドの詳細については『高度なメモリ管理プログラミングガイド』を参照してください。

解放されたオブジェクトが所有していたデータまたはインスタンス変数に、動的にストレージを割り当てるなど、オブジェクトによる任意に追加されたメモリ消費を解放するためには、独自バージョンのdeallocをサブクラスで実装する必要があります。

クラス固有の解放を行った後、サブクラスメソッドはsuper:にスーパークラス用のdeallocメッセージを渡すように組み込む必要があります。

- (void)dealloc {
    [companion release];
    NSZoneFree(private, [self zone])
    [super dealloc];
}

重要:工程のメモリが終了時に自動的にクリアされている場合、アプリケーション終了時にdeallocメッセージが送信できないことがあります。
OSがリソースのクリーンアップを全てのメモリ管理メソッドを呼び出すのに比べて、その方がより効率的です。
その他の理由も含め、deallocで不足がちなリソースの管理をしないでください。
詳細は『高度なメモリ管理プログラミングガイド』を参照してください。

特別な考慮事項

ガベージコレクションが有効な場合、ガベージコレクションはdeallocの代わりにfinalizeをレシーバに送信します。
ガベージコレクションが有効な場合、このメソッドは何もしません。

(編注:現在、iOSはガベージコレクションに対応していません)



参考文献

NSObject Class Reference

はじめてのiPhone3プログラミングはじめてのiPhone3プログラミング
(2009/12/17)
Dave Mark、Jeff LaMarche 他

商品詳細を見る






Wave SoundTouch music system IV
0 Comments
Leave a comment
管理者にだけ表示を許可する
Top
0 Trackbacks
Top
Calendar
06 | 2017/07 | 08
Sun Mon Tue Wed Thu Fri Sat
- - - - - - 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 - - - - -
Recent Articles
iTunes


Swift
Categories
Tips
Profile

水月杏香

Author:水月杏香
永遠の初心者プログラマ。

Wish List
WACOM


ARC
Technical Q&A
情報プロパティリストキー
Start Developing iOS Apps Today
BOSE

Wave SoundTouch music system IV
Reference
NSApplicationDelegateプロトコル
NSArrayクラス
NSAutoreleasePoolクラス
NSBundleクラス
NSBundle UIKit追加分
NSCalendarクラス
NSCoderクラス
NSCodingプロトコル
NSCopyingプロトコル
NSDataクラス
NSDateクラス
NSDateFormatterクラス
NSDictionaryクラス
NSEntityDescriptionクラス
NSEnumeratorクラス
NSErrorクラス
NSExceptionクラス
NSFetchRequestクラス
NSFileHandleクラス
NSFileManagerクラス
NSIndexPathクラス
NSIndexPath UIKit追加分
NSKeyedArchiverクラス
NSKeyedUnarchiverクラス
NSKeyValueCodingプロトコル
NSLocaleクラス
NSManagedObjectクラス
NSManagedObjectContextクラス
NSManagedObjectModelクラス
NSMutableArrayクラス
NSMutableCopyingプロトコル
NSMutableDictionaryクラス
NSMutableSetクラス
NSNotificationクラス
NSNotificationCenterクラス
NSNullクラス
NSNumberクラス
NSObjectクラス
NSObject UIKit追加分
NSObjectプロトコル
NSPersistentStoreクラス
NSPersistentStoreCoordinatorクラス
NSPredicateクラス
NSPropertyListSerializationクラス
NSRunLoopクラス
NSSetクラス
NSStringクラス
NSString UIKit追加分
NSTimerクラス
NSTimeZoneクラス
NSURLクラス
NSURLProtectionSpaceクラス
NSURLRequestクラス
NSUserDefaultsクラス
NSValueクラス

UIActionSheetクラス
UIActionSheetDelegateプロトコル
UIActivityIndicatorViewクラス
UIAlertViewクラス
UIAlertViewDelegateプロトコル
UIApplicationクラス
UIApplicationDelegateプロトコル
UIBarButtonItemクラス
UIBarItemクラス
UIButtonクラス
UIColorクラス
UIControlクラス
UIDatePickerクラス
UIDeviceクラス
UIEventクラス
UIFontクラス
UIGestureRecognizerクラス
UIImageクラス
UIImageViewクラス
UIKit Function
UILabelクラス
UINavigationControllerクラス
UINavigationItemクラス
UIPickerViewクラス
UIPickerViewDataSourceプロトコル
UIPickerViewDelegateプロトコル
UIPinchGestureRecognizerクラス
UIResponderクラス
UIScreenクラス
UIScrollViewクラス
UISearchBarクラス
UISearchBarDelegateプロトコル
UISegmentedControlクラス
UISliderクラス
UISwipeGestureRecognizerクラス
UISwitchクラス
UITableViewクラス
UITableViewCellクラス
UITableViewControllerクラス
UITableViewDataSourceプロトコル
UITableViewDelegateプロトコル
UITapGestureRecognizerクラス
UITextFieldクラス
UITextFieldDelegateプロトコル
UITextInputTraitsプロトコル
UITextViewクラス
UITextViewDelegateプロトコル
UIToolbarクラス
UITouchクラス
UIViewクラス
UIViewControllerクラス
UIWebViewクラス
UIWebViewDelegateプロトコル
UIWindowクラス

AVAudioPlayerクラス
AVAudioPlayerDelegateプロトコル

CADisplayLinkクラス
CAEAGLLayerクラス
CALayerクラス

CGAffineTransform
CGBitmapContext
CGColor
CGColorSpace
CGContext
CGGeometry
CGImage
CGPath

EAGLContextクラス
EAGLDrawableプロトコル

Foundation Constants
Foundation Data Types
Foundation Functions

MPMediaItemクラス
MPMediaItemArtworkクラス
MPMediaPlaylistクラス
MPMediaPropertyPredicateクラス
MPMediaQueryクラス
MPMusicPlayerControllerクラス

Randomization Services

System Sound Services
Amazon


OpenGL ES
SQLite
Monthly Archives
Recent Comments
Recent TrackBacks
RSS Link
Visitors
QR Code
QR