詳解Swift(14)〜C/Objective-Cとのデータ受け渡し

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



CHAPTER 14 C/Objective-Cとのデータ受け渡し



●14.1 データ型の互換性


・返されたポインタから値を取り出す

List14-3 において、本文中ではプレイグラウンドで動作しないとありますが、現在は問題なく動作します。

関数 ctime() の返り値は UnsafeMutablePointer<Int8> ですが、

let p = ctime(&current)
p.dynamicType        // UnsafeMutablePointer<Int8>.Type

その返り値 p を(本書にあるように UInt8 ではなく)Int8 に変換し、UnicodeScalar に更に変換しようとするとエラーになります。

print(UnicodeScalar(Int8(p[i])), terminator:"")        // error: cannot invoke initializer for type 'UnicodeScalar' with an argument list of type '(Int8)'

これは UnicodeScalar のイニシャライザが Int、UInt16、UInt32、UInt8 に対応しているものの Int8 には対応していないからかもしれません。
(「Apple Developer Documentation/Swift Standard Library/UnicodeScalar」参照)

もちろん定数 p を UnsafeMutablePointer で初期化する際も <Int8> ではなく本書にある通り <UInt8> で初期化する必要があります。

let p = UnsafeMutablePointer<UInt8>(ctime(&current))
for i in 0..<25 {
    print(UnicodeScalar(p[i]), terminator:"")        // Thu Nov 10 23:57:13 2016 など
}


・コマンドラインの引数リストにアクセスする

C_ARGC と C_ARGV は、iOS 8.3(Xcode 6.3(Swift 1.2)?)で削除されたようです。
(「Swift Changes/iOS 8.3 API Diffs」参照)


・Cの標準関数と文字列

プレイグラウンドで Resources に output.dat ファイルを作成して試そうとしましたが、書き込みや追加書き込みモードではファイルが開けなかったので断念しました。

let path = (NSBundle.mainBundle().pathForResource("output", ofType: "dat"))!
var fp: UnsafeMutablePointer<FILE> = fopen(path, "r")        // 成功
var fp: UnsafeMutablePointer<FILE> = fopen(path, "w")        // 失敗
var fp: UnsafeMutablePointer<FILE> = fopen(path, "a")        // 失敗


・T**型の引数の扱い

List14-7 は著者の目的と少々離れる修正が必要となります。

まず変数 err は変更されないので定数にしてはどうかという警告が出ます。

var err: NSError? = nil        // warning: variable 'err' was never mutated; consider changing to 'let' constant

let err: NSError? = nil

ただし最終的に err は使用しません。

次に変数 cont ですが入力補完で気付くように contentsOfFile:encoding:error は使用できません。

var cont = NSString(contentsOfFile: path, encoding: NSASCIIStringEncoding, error: &err)
// error: argument labels '(contentsOfFile:, encoding:, error:)' do not match any available overloads

これに関しては「teratail/CSV - CSVファイルを読み込む実装でString型に変換する時処理が止まる(30501)」にあるように、Swift 2.0 で contentsOfFile:encoding:error が廃止になり、代わりに try? 演算子を使用したオプショナル束縛構文に書き換える必要があるようです。

その場合 try? 演算子はエラーが発生した場合に nil を返すため、エラー内容を保持する定数 err が不要になり、cont が nil かどうかを判定する if 文は文字列 "error" を返すだけになるので、オプショナル束縛構文に組み込んだ方が良いでしょう。

またファイルの読み込みに成功した場合の cont は String 型の定数に、失敗した場合は単に文字列 "error" を返すだけになりますので、関数 readfile の返り値は NSString 型にします。

以上の修正を行った関数 readfile は以下のようになります。

func readfile(path:String) -> NSString {
    if let cont = try? NSString(contentsOfFile: path, encoding: NSASCIIStringEncoding) {
        return cont
    }else {
        return "Error"
    }
}

したがって存在しないファイルパス "nobody" を指定して実行した場合、残念ながらエラー内容を出力できず単に "Error" という文字列が返ります。

readfile("nobody")        // Error


Resources に適当な文字列を入れたテキストファイル(ここでは output.dat )を追加した場合は以下のようになります。

let path = (NSBundle.mainBundle().pathForResource("output", ofType: "dat"))!
readfile(path)        // Where do we come from? What are we? Where are we going?



●14.2 対応付けられたデータ型


・配列

詳解Swift(8)〜クラスと継承」で述べたように、現在は AnyObject 型の定数・変数を as 演算子でダウンキャストすることはできませんので、as? 演算子でオプショナル型として返すか、as! 演算子で強制ダウンキャストすることになります。

AnyObject 型配列の定数 elm の要素が全て文字列の場合、as? ならオプショナル String 型配列、as! なら String 型配列が返りますが、文字列以外の要素が混在している場合は前者は nil が返り、後者では致命的エラーが発生します。

let elm: [AnyObject] = ["スノードロップ", "カトレア", "ナイトフロックス", 2]
var strelm0 = elm as [String]        // error: '[AnyObject]' is not convertible to '[String]'; did you mean to use 'as!' to force downcast?
var strelm1 = elm as? [String]       // nil
var strelm2 = elm as! [String]      // fatal error: array cannot be bridged from Objective-C

また AniyObject 型配列 elm から高速列挙で String 型の要素を取り出した場合は String 型配列になりますが、クロージャの場合は AniyObject 型配列になります。

var strelm_ = elm.filter{ $0 is String }
strelm_.dynamicType        // Array<AnyObject>.Type
print(strelm_)        // [スノードロップ, カトレア, ナイトフロックス]


・辞書

配列と同様に、as 演算子ではエラーになるので as? 演算子または as! 演算子を使用することになります。

let pinfo = info as [String:Int]        // error: 'NSDictionary' is not convertible to '[String : Int]'; did you mean to use 'as!' to force downcast?

let pinfo = info as? [String:Int]        // ["Level": 5, "Height": 161, "Grade": 2]


・NSValue

プレイグラウンドで試してみます。
(「Stack Overflow/ios - How to convert CGPoint in NSValue in swift?」参照)

var size = CGSize(width: 2, height: 3)
size.dynamicType        // __C.CGSize.Type
var val = NSValue(CGSize: size)        // NSSize: {2, 3}
val.dynamicType        // NSConcreteValue.Type

var sz = CGSize()
val.getValue(&sz)
print(sz)        // (2.0, 3.0)

NSConcreteValue クラスは NSValue クラスのサブクラス(コンクリートクラス)です。
(「こたつつきみかん/見えないクラス群」、「マイナビニュース/ダイナミックObjective-C (32) 抽象クラスとクラスクラスタ」参照)



Apple Developer Documentation/Swift Standard Library/UnicodeScalar

Swift Changes/iOS 8.3 API Diffs

teratail/CSV - CSVファイルを読み込む実装でString型に変換する時処理が止まる(30501)

Stack Overflow/ios - How to convert CGPoint in NSValue in swift?

こたつつきみかん/見えないクラス群

マイナビニュース/ダイナミックObjective-C (32) 抽象クラスとクラスクラスタ

詳解 Swift 改訂版(Amazon)
 






QuietControl 30 wireless headphones
0 Comments
Leave a comment
管理者にだけ表示を許可する
Top
0 Trackbacks
Top
Calendar
04 | 2017/05 | 06
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

QuietControl 30 wireless headphones
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