higan96技術メモ

https://github.com/higan96

CompleteHandlerのないアニメーションにCATransactionでCompleteHandlerを追加する

タイトルの通りです。 CompleteHandlerのないアニメ―ションにCompleteHandlerを追加します。 下の例ではUITableViewediting modeの終了アニメーション後に処理を追加しています。

CATransaction.begin()
CATransaction.setCompletionBlock { () -> Void in
// some code
}
setEditing(false, animated: true)
CATransaction.commit()

対象になるアニメーションの処理(setEditing)をCATransaction.begin()CATransaction.commit()で囲んで、CATransaction.setCompletionBlockにやりたい処理を書きます。

複数のUITextFieldとUITextViewが混在するViewControllerでキーワードを閉じる

通常、であればViewConrollerUITextFieldDelegateUIViewControllerを適用して、textFieldShouldReturnだったり何かしらのタッチイベントでtextField.resignFirstResponder()をすると思います。

ただ、UITextFieldとUITextViewが混在する場合、どちらが編集状態かわからないけど、とにかくキーボードを閉じたい時がある。そういう時はViewControllerのインスタンスプロパティのviewに対してendeditingすればいい。

self.view.endEditing(true)

viewのサブビュー全ての編集状態が終了するので、どちらかの判定を含まず、シンプルにキーボードを閉じることができる。

UITableViewで無限スクロール

func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
  if indexPath.row == (items.count - 1){
    items += nextItems
    tableView.reloadData()
  }
}

最後のcellに来たらnextItemsを追加しています。

たまにcellForRowAtIndexPathでこの処理をしている記事を見るけど、cellForRowAtIndexPathはあくまで初期化処理に徹するべきだと思うので、willDisplayCellで処理を記述しています。

実際の使用シーンではnextItemsの取得処理が入ると思います。

また、自分の場合、一番下にスクロールしたのが分かるように「ロード中」のようなテキストを表示するfooterを指定しています。その場合、固定表示したくないので、viewDidLoadで下のように指定してます。

tableView.tableFooteView = footer

linker command failed with exit code 1 (use -v to see invocation)の対処

file too small (length=0) file '/some/file/path' for architecture x86_64
linker command failed with exit code 1 (use -v to see invocation)

command + shift + k

これでだいたい解決する

多分ビルドが失敗したときに、変な風に(0byte)書き換わってるのが原因ぽい

OHHTTPStubとXCTestで、モックを使った非同期処理をテストする

通信をモックを使って、実際のサーバーサイドやWebAPIとの通信を行わずにテストする。

import UIKit
import XCTest

class SomeAPIClientTests: XCTestCase {
    let someAPIClient = SomeAPIClient()

    override func setUp() {
        super.setUp()
    }
    
    override func tearDown() {
        super.tearDown()
    }

    func testExample(){
        let obj = SomeObject()
        let stub:NSDictionary = ["id": 1]
        let expectation = self.expectationWithDescription("非同期通信は完了する")
        let stubDesc = OHHTTPStubs.stubRequestsPassingTest({ (request: NSURLRequest!) -> Bool in
            // 通信処理をモックを通して行なうか、の条件。trueを返すときに、モックを通す
            return true
            }, withStubResponse:( { (request: NSURLRequest!) -> OHHTTPStubsResponse in
                //レスポンス
                //失敗させたいときはステータスコードをいじるなどする
                return OHHTTPStubsResponse(JSONObject: stub, statusCode: 200, headers: ["Content-Type" : "text/json"])
            })
        )
        
        someAPIClient.post(obj, callback: {(postedObj, error) -> () in
            XCTAssertNil(error, "Error should be nil.")
            //通信が正常に行われたこと、失敗したことをテストしても意味がないので、実際にはそれぞれのケースで行われる処理をテストする。
            //expectation.fulfill()が呼ばれたことが、このテストの非同期処理が正常に行われたことを意味する。
            expectation.fulfill()
        })
        
        self.waitForExpectationsWithTimeout(5, handler: {(error) -> Void in
            //expectation.fulfill()が呼ばれたタイミングで実行される。
            //ここでOHHTTPStubsを消しておかないと、
            //他のテストの通信もこのテストの設定のモックが使用されてしまう。
            OHHTTPStubs.removeAllStubs()
            return
        })
    }
}

UIViewを45度傾かせる

吹き出しようの「ぺろっ」と出てている三角形を作りたかったので、正方形を45度傾かせて実現しました。 この辺の数学的知識が無いので、解説はできません。

let angle = CGFloat(M_PI * (45) / 180.0)
//miniBoxはUIViewのインスタンス
miniBox.transform = CGAffineTransformMakeRotation(angle)