詳解Swift(8)〜クラスと継承

2016. 08. 13
この記事は詳解 Swift(初版第1刷)を元に、Xcode 7.3.1(Swift 2.2)下における差異を記述しています。



CHAPTER 08 クラスと継承



●8.1 クラス定義


・継承と型推論

クラス SOS は「SBクリエイティブ:詳解 Swift サンプルダウンロード」に記述されています。

継承関係がないクラスのインスタンス同士をまとめる場合、AnyObject 型を指定しないと型推論では NSArray 型になるので注意が必要です。

class SOS { var name = "" }        // サンプルコード:p160.swift

var all = [ Time12(hour:0, min:15), SOS() ]        // 変数 all に AnyObject 型を指定しない場合
all.dynamicType        // __NSArrayI.Type

また本書では AnyObject 型の変数を as 演算子で Time12 型にキャストしていますが、現在は変換できないとエラーがでます。
as! 演算子(「人生と仕事を楽しむブログ/Swiftのas! 演算子」を参照)で強制ダウンキャストすることは可能です。

var all:[AnyObject] = [ Time12(hour:0, min:15), SOS() ]
all.dynamicType        // Array<AnyObject>.Type
print( (all[0] as Time12).description() )        // error: 'AnyObject' is not convertible to 'Time12'; did you mean to use 'as!' to force downcast?
print( (all[0] as! Time12).description() )        //  0:15 AM

AnyObject 型の時点で特定の型にキャストできるかどうかは定かではありませんので、戻り値はオプショナル型として考えるのが自然です。
もちろん強制ダウンキャストは当該型であると確定できる場合のみ使用すべきで、通常はオプショナル束縛構文などを利用することになるでしょう。

print( (all[1] as! Time12).description() )        //  Could not cast value of type 'SOS' (0x1145fc230) to 'Time12' (0x1145fc120).

if let a = all[0] as? Time12 {
    print(a.description())        //  0:15 AM
}

Any 型も同様です。

print( (every[0] as Time12).description() )        // error: 'Any' (aka 'protocol<>') is not convertible to 'Time12'; did you mean to use 'as!' to force downcast?
print( (every[0] as! Time12).description() )        //  4:30 PM

switch 文によるパターンマッチの場合は当該型でない時の処理も記述しますので as 演算子で構いません。



●8.2 イニシャライザ


・クラス継承の例題

曜日の計算に使用するツェラーの公式の関数 dayOfWeek は、「詳解Swift(2)〜関数」で述べたように Swift 3 で仮引数を変数にすることができなくなるので修正する必要があります。

またクラス DateW2 においてサブクラスで追加した変数 dweek を定数にした例を示していますが、「詳解Swift(3)〜構造体」で述べたように Swift 1.2 から定数(let)プロパティは再割り当てできなくなりましたので、スーパークラスへのデリゲート後に(初期値の設定の有無に関わらず)サブクラスで追加した定数への代入はできません。

class DateW2 : Date {
    let dweek = String()        // 定数に変更
    override init(_ y: Int, _ m: Int, _ d: Int) {
        super.init(y, m, d)
        dweek = namesOfDay[dow]        // error: immutable value 'self.dweek' may only be initialized once
    }
}


・初期化は結局どう記述すればよいのか

「(3) スーパークラスがあり、その指定イニシャライザを呼び出す場合」において、前述の通り定数に仮の初期値を与えてスーパークラスの初期化後に実際の値を代入するという手法は使えません。


・必須イニシャライザ

クラス Icocai で定数 idnumber に初期値を設定していますが、イニシャライザで変更しているためエラーが出ます。
今回の場合、変更は一度きりで且つスーパークラスのイニシャライザを呼び出す前の変更ですので、値の性質から見ても初期値を与えず定数のままにすると良いでしょう。

let idnumber : Int = 0        // error: immutable value 'self.idnumber' may only be initialized once を引き起こす
let idnumber : Int        // 初期値を未設定に


また必須イニシャライザ内で変数 icocaiSerial を前置インクリメントしていますが、インクリメント/デクリメント演算子は Swift 3.0 で削除するため廃止になったので修正する必要があります。

idnumber = ++icocaiSerial        // warning: '++' is deprecated: it will be removed in Swift 3
icocaiSerial += 1        // インクリメント演算子を使わない形式に
idnumber = icocaiSerial



●8.3 開放時処理


・デイニシャライザを使った例

List8-14 を iOS Platform のプレイグラウンドで試す場合、UIKit がインポートされているので Foundation や Darwin を別途インポートする必要はありません。

クラス ReadWord の関数 nextWord() 内で do-while 文を使用していますが、「詳解Swift(1)〜Swiftでプログラミング」で述べたように do-while は repeat-while に名称変更されたので修正する必要があります。

クラス ReadWord の動作確認に使用する text.txt ファイルは「SBクリエイティブ:詳解 Swift サンプルダウンロード」の Chap08 フォルダ内にあります。

関数 readIt() で text.txt ファイルを指定していますが、プレイグラウンドで試す場合は ReadWord の引数として単純に「text.txt」を渡すだけではファイルを開くことができません。
プレイグラウンドでテキストファイルを読み込むには Resources にテキストファイルを追加し、そのファイルパスを渡す必要があります。
まず Xcode のメニューで View/Navigators/Show Project Navigator を選択し、Resources フォルダに text.txt ファイルをドラッグ&ドロップして追加します。

8044.png

次に「Qiita/playground でファイル読み込みをする (画像・テキストファイルなど)」を参考に pathForResource メソッドで Resources に追加した text.txt ファイルのパスを取得しますが、戻り値がオプショナル String 型なので開示する必要があります。
後は ReadWord の引数として "text.txt" の代わりにパスを渡すだけです。

// プレイグラウンドのResourcesフォルダに追加したtext.txtファイルのファイルパスを取得
let path = (NSBundle.mainBundle().pathForResource("text", ofType: "txt"))!

func readIt() {
    if let reader = ReadWord(open: path) {



●8.4 遅延格納型プロパティ


・ファイルの属性を遅延評価する例題

前述の通りList8-15 を iOS Platform のプレイグラウンドで試す場合、FileAttr の引数には単純に「text.txt」を指定するのではなく、 Resources に text.txt ファイルを追加してそのパスを取得する必要があります。

let d = FileAttr(file: "text.txt")        // ファイルを認識できず、size では 0 が返ってくる

let path = (NSBundle.mainBundle().pathForResource("text", ofType: "txt"))!
let d = FileAttr(file: path)
print(d.filename)        // /var/folders/_f/(中略)/T/com.apple.dt.Xcode.pg/resources/(中略)/text.txt

プロパティ filename には Resources に含まれている text.txt へのファイルパスが格納されています。



●8.5 アクセス制御


・プロパティのアクセス制御

List8-17 でクラス継承と可視性の例を示していますが、現在プレイグラウンドで試すことはできないようです。

プレイグラウンドで別のソースファイルを追加するには、プロジェクトナビゲータを開き(Xcode のメニューで View/Navigators/Show Project Navigator を選択)Sources フォルダを右クリックして New File を選択します。

8045.png

以下、Sources フォルダに追加したファイルをサポートコード、通常のプレイグラウンドで開いているファイル(実体は Contents.swift )をメインコードとここでは呼称し説明します。


サポートコードでクラス定義、メインコードで実行した場合)

サポートコード(例えば camera.swift など)で List8-17 のクラス定義をし、メインコードで実行しようとすると、
WebCamera のインスタンス生成時にエラーが出ます。

var cam = WebCamera()        // error: use of unresolved identifier 'WebCamera'

これは「XCode 7.1 日本語化計画-Xcode 7.2 Playground Help/Playground について/プレイグラウンドに補助コードの追加」や「いものやま。/Swiftをプレイグラウンドで使ってみた。」で解説されているように、サポートコードはモジュールとして組み込まれメインコードはモジュール外の扱いになるため、クラス定義に public を指定しないとメインコードからは見えないからです。


サポートコードのクラス定義に public を指定し、メインコードで実行した場合)

WebCamera クラスを public にしようとするとスーパークラスである USBCamera が internal であるためエラーが出ます(Class cannot be declared public because its superclass is internal)。

そして USBCamera も public にしたところで初期化に失敗しますし、本来の趣旨とは離れてしまうので意味がありません。

var cam = WebCamera()        // error: 'WebCamera' cannot be constructed because it has no accessible initializers


サポートコードでクラス定義と実行をした場合)

クラス定義を camera.swift、実行を main.swift などとして両方をサポートコードにした場合、インスタンス生成はできるのですが、以降はトップレベルでは許可されていない表現として蹴られます。
(「articles of samekard/Swiftのコンパイルエラー寄せ集め」参照)

var cam = WebCamera()
cam.focus = 4.0        // Expressions are not allowed at the top level
print(cam.shutterSpeed)        // Expressions are not allowed at the top level
cam.take()        // Expressions are not allowed at the top level
cam.shutterSpeed = 1.0 / 1000.0        // Expressions are not allowed at the top level
print(cam.shutterSpeed)        // Expressions are not allowed at the top level


というわけでプレイグラウンドでこの可視性を確認することはできませんでした。
ちゃんとしたプロジェクトやコマンドラインでは上手くいくものと思われますが、ここでは割愛します。



GitHub/Array Basic

人生と仕事を楽しむブログ/Swiftのas! 演算子

Qiita/playground でファイル読み込みをする (画像・テキストファイルなど)

Objective-CとXcodeでiPhoneアプリを作ろう/Objective-Cで使用できる関数

C言語関数辞典

使って創ってApp/Swift2.1で10進数を2進数・8進数・16進数に変換する

kazmax - Linuxで自宅サーバー/Linux コマンド集 一覧表/stat - システムコールの説明

筑波大学/古瀬一隆/情報メディア実験(講義資料)/マイクロデータベース管理システムの実装/怪奇? 「ファイルサイズ: 0」の謎

XCode 7.1 日本語化計画-Xcode 7.2 Playground Help/Playground について/プレイグラウンドに補助コードの追加

いものやま。/Swiftをプレイグラウンドで使ってみた。

articles of samekard/Swiftのコンパイルエラー寄せ集め

詳解 Swift 改訂版(Amazon)
 






Bose SoundSport wireless headphones
Calendar
07 | 2016/08 | 09
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
WACOM


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
BOSE

Bose SoundSport wireless headphones
ARC
Technical Q&A
情報プロパティリストキー
Start Developing iOS Apps Today
SQLite
OpenGL ES
Amazon


Monthly Archives
Recent Comments
Recent TrackBacks
RSS Link
Profile

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

QR Code
QR
Visitors