なんとかするから、なんとかなる

エンジニア関係のことを書きます

iOS How to wait for the async procedure in XCTest

Introduction

This article shows how to wait for an async procedure like API Request or some closure.

Solution

It is easy to wait an async procedure using "expectation"

Sample Code

let request = SomeRequest()
let expect = expectation(description: "SendMyRequest")
APIClient.send(request: request) { (result) in
    switch result {
    case .success(let response):
        expect.fulfill()
    case .failure(let error):
        XCTFail("Failuer in API Client")
    }
}
waitForExpectations(timeout: 5) { (error) in
    if let error = error {
    // Some error occured like network error.
        print(error)
        XCTFail("ExpectaionTimeOut")
    } else {
    // Finished with no error.
    }
}

Detail

At first, declare the expectation with some identifier.

let expect = expectation(description: "SOME IDENTIFIER FOR THE LOG")

To expect the above valuable.

Call the fulfill method when an async procedure finished.

expect.fulfill()

At last, call the waitForExpectations(timeout:handler:) method with time out duration and completion handler.

waitForExpectations(timeout: 5) { (error) in
    // Do something if you want. If some error happened, the error value is not nil.
}

iOS XCTestで非同期処理の完了を待つ

English version below

はじめに

タイトル通りです。

APIRequestなどXCTestで疎通確認をした際に、非同期処理の完了を待ちたいことはよくあります。

その方法を簡単に紹介

解決方法

expectationを使います。

次のように書いて待つことを宣言

let expect = expectaion(description: "テストログ用の文字列")

上記のexpectが満たされたこと示すために、非同期処理完了時にfulfillを呼びます。

expect.fulfill()

最後にwaitForExpectations(timeout:handler:)でタイムアウト時間などを指定して、完了時の処理をhandlerに渡します。

waitForExpectations(timeout: 5) { (error) in
    // 何かの処理
}

ね。簡単でしょ。

サンプルコード

こんな感じで使います。

let request = SomeRequest()
let expect = expectation(description: "SendMyRequest")
APIClient.send(request: request) { (result) in
    switch result {
    case .success(let response):
        expect.fulfill()
    case .failure(let error):
        XCTFail("Failuer in API Client")
    }
}
waitForExpectations(timeout: 5) { (error) in
    if let error = error {
    //なにかしらエラー発生(タイムアウトなど)
        print(error)
        XCTFail("ExpectaionTimeOut")
    } else {
    //問題なく完了
    }
}

iOS How to solve the error message about Module was not compiled for testing

Introduction

This article shows how to solve the error message about “Module was not compiled for testing” on XCTest code.

The module was installed by Carthage.

Background

When I try to do my test code on the XCTest, sometimes I would like to use some modules which was installed by Carthage.

import XCTest

@testable import {Your Project}

Using “import” sentence

At first, I tried to use the import sentence to use the module as below.

import "SOME MODULE"

I faced on the error message.

framework not found

Using “@testable” sentence

Secondly, I tied to se the @testable sentence as below.

@testble import "SOME MODULE"

Xcode gave me another error message.

Module "SOME MODULE" was not compiled for testing

Solution

It need to include the module at the

[TestTarget] -[Target] - [BuildPhases] - [Link Binary With Libraries]

f:id:hopita:20180828233512p:plain

It works fine!

iOS Carthageでモジュールを導入してXCTestで Module "なにかしらのモジュール" was not compiled for testing が出たときの対処方法

English version below

はじめに

XCTestでユニットテストを実行し用としたときにぶつかった問題です。

Carthageでモジュールを導入し、ユニットテストでそのモジュールを使用するときに少しつまづきました。

背景

XCTestで自身のプロジェクトをテストするとき、次のように書くと思います。

import XCTest

@testable import {Your Project}

今回はテストケースの中でモジュールを利用して、何かしら処理を実施しようとしたときに躓きました。

モジュールはCarthageを利用してプロジェクトに導入しています。

単純にimportしてみる

例えば次のように書くと

import "なにかのモジュール"

次のようなエラーが出ました

framework not found

@testableをつけてみる

別の方法で次のように書くと

@testble import "なにかのモジュール"

次のようなエラーが出ました

Module "なにかのモジュール" was not compiled for testing

対処方法

[Target] - [TestTarget] - [BuildPhases] - [Link Binary With Libraries] で対象のモジュールを指定する。

f:id:hopita:20180828233512p:plain:w400

iOS ForEach構文でArrayのIndexを取得する

English version below

はじめに

ForEach文でIndex番号が欲しいことはよくあるので、備忘録です。

解決方法

enumerated()メソッドを利用する

for (index, value) in someArray.enumarated() {
    // なにかやりたい処理
}

iOS How to edit a View in debug mode by LLDB Console

Introduction

This article shows how to edit a view in debug mode by LLDB Console.

Preparation

First of all, Build an app on a simulator or device and open the [Debug View Hierarchy]

f:id:hopita:20180824213110p:plain

In this article, I'll show you how to change an information for UILabel.

Let's see a memory address at the view

After opening the [[Debug View Hierarchy], click the right button and select the [Print Description of UILabel] menu on the view you want to edit.

Then, on the lldb console shows the details of information for the view.

Printing description of $12:
<UILabel: 0x7fb65a6075a0; frame = (0 0; 250 20.3333); text = 'YOUR TEXT'; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x6000000975c0>>

For the latter procedures, copy the memory address "0x7fb65a6075a0".

Let's see the information of the view by memory address

Let's see the information by the memory address as below.

Command

po ((UILabel *) 0x7fb65a6075a0)

Result

<UILabel: 0x7fb65a6075a0; frame = (0 0; 250 20.3333); text = ''YOUR TEXT'; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x6000000975c0>>

In this time, you can see the same information as before you see.

Let's change the text string in the UILabel

By this command, you can edit the text string on the UILabel

e [[(UILabel *) 0x7fb65a6075a0) setText:@"newText"]

"e" is an alies of expression. It doesn't take care about which command you typed.

Let's reflection the changes immediately

By the procedure as you see before, the lldb console shows the string '$0 = "newText"'.

But on the simulator or device, it didn't reflect the changes yet.

If you press the continue button, it will be reflected soon.

In this time, let's reflect it immediately.

Try this command on the lldb console.

e (void)[CATransaction flush]

On the simulator or device, the changes will be reflection fine.