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

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

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 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.

iOS UIViewControllerでバックグラウンドへの遷移を検知する

English version below.

はじめに

UIViewControllerにおいて、アプリがバックグラウンドなったときやバックグラウンドに戻ってきたときに処理を行いことはよくあります。

今回はそのやり方を紹介したいと思います。

解決方法

ご存知の通り、UIViewControllerにはバックグラウンドになったときやバックグラウンドから戻ってきたときのデリゲートはありません。

なので、次のようにNotificationCenterに登録するしかありません。

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(viewWillEnterBackground), name: .UIApplicationWillResignActive, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(viewDidEnterBackground), name: .UIApplicationDidEnterBackground, object: nil)
        
    NotificationCenter.default.addObserver(self, selector: #selector(viewWillEnterForeground), name: .UIApplicationWillEnterForeground , object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(viewDidBecomeActive), name: .UIApplicationDidBecomeActive , object: nil)
}

@objc func viewWillEnterBackground() {
    // バックグランドへ遷移前に呼ばれる
}
   
@objc func viewDidEnterBackground() {
    // バックグラウンドへ遷移後に呼ばれる
}
    
@objc func viewWillEnterForeground() {
    // バックグラウンドから遷移してくるときに呼ばれる
}
    
@objc func viewDidBecomeActive() {
    // バックグラウンドから遷移してきたときに呼ばれる
}

iOS How to detect the background transition in UIViewController

Introduction

This article shows hot to detect an entering background and activating from background in UIViewController.

Solution

As you know, UIViewController doesn't have a delegate which is called when it will go background and come back from it.

So, the only way to receive those events is register the UIViewController to a NotificationCenter as below.

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(viewWillEnterBackground), name: .UIApplicationWillResignActive, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(viewDidEnterBackground), name: .UIApplicationDidEnterBackground, object: nil)
        
    NotificationCenter.default.addObserver(self, selector: #selector(viewWillEnterForeground), name: .UIApplicationWillEnterForeground , object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(viewDidBecomeActive), name: .UIApplicationDidBecomeActive , object: nil)
}

@objc func viewWillEnterBackground() {
    // called when app will enter background
}
    
@objc func viewDidEnterBackground() {
    // called when app entered background
}
    
@objc func viewWillEnterForeground() {
    // called when app will be foreground
}
    
@objc func viewDidBecomeActive() {
    // called when app become active
}