Microsoft Azure Mobile Servicesのサンプルアプリをswiftで書き直して、Pull Request を行いました。
残念ながらこの Pull Request は取り込まれなかった(私が行った二日後ぐらいに、別のPull Requestで同等の機能を中の人が実装したから。「ちょっ、おまwwwww」っていう感じだけど。)のですが、そのときにいろいろとノウハウが貯まったので対処をまとめました。
dyld: Library not loaded: @rpath/libswift_stdlib_core.dylib
というエラーメッセージが出てアプリが起動しない
手始めにmain.m
を削除してとQSAppDelegate.swift
に置き換えたらこれが出てハマりました。
Xcodeを再起動したら直りました。
'AnyObject[]' does not have a member named 'mutableCopy'
NSArrayをmutableCopyしてNSMutableArrayに入れようとしたらエラー。キャストではなく、NSMutableArrayのコンストラクタで返すようにしたらうまくいったっぽい。
// 修正前
var items = results.mutableCopy() as NSMutableArray
// 修正後
var items = NSMutableArray(array:results)
Ambiguous use of 'NSNotFound'
iPhone5sでビルドしていたときは良かったけど、iPhone5やiPhone4sでビルドしたらなぜか上記エラーでビルドが通らなくなった。多分、#ifでプラットフォームごとに読み込むヘッダーを変えているからだと思われる。Foundation.NSNotFound
とすることで解消した。
// 修正前
if (index != NSNotFound) { //... }
// 修正後
if (index != Foundation.NSNotFound) { //... }
ブロックのメソッド定義と呼び出し方
これは慣れるとそうでもないんだけど、慣れるまでわけわからなかった。
空のブロックの場合
空の場合はそんなに違いないですかね。
objective-c
// 定義
typedef void (^QSCompletionBlock) ();
- (void)refreshDataOnSuccess:(QSCompletionBlock)completion;
// 呼び出し方
[self.todoService refreshDataOnSuccess:^
{
if (self.useRefreshControl == YES) {
[self.refreshControl endRefreshing];
}
[self.tableView reloadData];
}];
swift
// 定義
func refreshDataOnSuccess(completion:()->Void)
// 呼び出し方
todoService.refreshDataOnSuccess({() in
if (self.useRefreshControl == true) {
self.refreshControl.endRefreshing()
}
self.tableView.reloadData()
})
引数が一つあるブロックの場合
swiftでのポイントは呼び出し時のブロックに型を指定しないことですかね。
swift での NSUInteger は UInt ではなく、Int で良いみたいです。UInt も用意されているようだけど。
Swift bridges NSUInteger and NSInteger to Int. Both of these types come over as Int in Foundation APIs.
Working with Cocoa Data Typesより
objective-c
// 定義
typedef void (^QSCompletionWithIndexBlock) (NSUInteger index);
- (void)addItem:(NSDictionary *)item
completion:(QSCompletionWithIndexBlock)completion;
// 呼び出し方
[self.todoService addItem:item completion:^(NSUInteger index)
{
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];
[view insertRowsAtIndexPaths:@[ indexPath ]
withRowAnimation:UITableViewRowAnimationTop];
}];
swift
// 定義
func addItem(item:NSDictionary, completion:(Int)->Void)
// 呼び出し方
todoService.addItem(item, completion:{index in
let indexPath = NSIndexPath(forRow:index, inSection:0)
view.insertRowsAtIndexPaths([indexPath], withRowAnimation:UITableViewRowAnimation.Top)
})
引数が3つあるブロックの場合
引数1つの時とあんまり変わらないです。
objective-c
// 定義
typedef void (^MSReadQueryBlock)(NSArray *items,
NSInteger totalCount,
NSError *error);
-(void)readWithPredicate:(NSPredicate *) predicate
completion:(MSReadQueryBlock)completion;
// 呼び出し方
[self.table readWithPredicate:predicate completion:^(NSArray *results, NSInteger totalCount, NSError *error)
{
[self logErrorIfNotNil:error];
items = [results mutableCopy];
// Let the caller know that we finished
completion();
}];
swift
// 定義
... 省略 ...
// 呼び出し方
table.readWithPredicate(predicate, completion:{results, totalCount, error in
self.logErrorIfNotNil(error)
self.items = NSMutableArray(array:results)
// Let the caller know that we finished
completion();
})
以上、swift対応で私が苦労した点でした。Pull Request はまたチャレンジしたいと思いますw