Objective-Cからswiftに書き直すときの対処まとめ


[Microsoft Azure Mobile Servicesのサンプルアプリ](https://github.com/Azure/azure-mobile-services/tree/master/quickstart/iOS/ZUMOAPPNAME)をswiftで書き直して、[Pull Request を行いました](https://github.com/Azure/azure-mobile-services/pull/279)。

残念ながらこの Pull Request は取り込まれなかった（私が行った二日後ぐらいに、[別のPull Request](https://github.com/Azure/azure-mobile-services/pull/284)で同等の機能を中の人が実装したから。「ちょっ、おまｗｗｗｗｗ」っていう感じだけど。)のですが、そのときにいろいろとノウハウが貯まったので対処をまとめました。

## `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のコンストラクタで返すようにしたらうまくいったっぽい。

```swift
// 修正前
var items = results.mutableCopy() as NSMutableArray

// 修正後
var items = NSMutableArray(array:results)

```

## Ambiguous use of 'NSNotFound'
iPhone5sでビルドしていたときは良かったけど、iPhone5やiPhone4sでビルドしたらなぜか上記エラーでビルドが通らなくなった。多分、#ifでプラットフォームごとに読み込むヘッダーを変えているからだと思われる。`Foundation.NSNotFound`とすることで解消した。

```swift
// 修正前
if (index != NSNotFound) { //... }

// 修正後
if (index != Foundation.NSNotFound) { //... }
```

## ブロックのメソッド定義と呼び出し方
これは慣れるとそうでもないんだけど、慣れるまでわけわからなかった。

### 空のブロックの場合
空の場合はそんなに違いないですかね。

#### objective-c
```objective-c
// 定義
typedef void (^QSCompletionBlock) ();
- (void)refreshDataOnSuccess:(QSCompletionBlock)completion;

// 呼び出し方
[self.todoService refreshDataOnSuccess:^
{
    if (self.useRefreshControl == YES) {
        [self.refreshControl endRefreshing];
    }
    [self.tableView reloadData];
}];
```

#### swift
```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](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/buildingcocoaapps/WorkingWithCocoaDataTypes.html)より

#### objective-c
```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
```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)
        })
```

### 引数が３つあるブロックの場合
引数１つの時とあんまり変わらないです。

#### objective-c
```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
```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 はまたチャレンジしたいと思いますｗ