ためすう

Swift から Objective-C のコードを呼ぶ方法

2019-01-31

目的

Objective-C から Swift を呼ぶ方法を調べました。

方法


Build Settings -> Swift Compiler – Code General の

```Bridging-Header.h``` が指定されているか確認します。

指定されている場合は、 import 文を書いていきます。

Bridging-Header.h

#import “Hoge.h” ```

参考

Swift、Objective-Cでバックグラウンド、フォアグラウンドへの遷移する方法

2019-01-28

目的

iOS アプリでバックグラウンドに遷移したとき、フォアグラウンドに遷移したときにある処理を実行する方法を調べました。

Notification 一覧

イベントタイミング Swift Objective-C
フォアグラウンドになる直前 NSNotification.Name.UIApplicationWillEnterForeground UIApplicationWillEnterForegroundNotification
アクティブになったら NSNotification.Name.UIApplicationDidBecomeActive UIApplicationDidBecomeActiveNotification
アクティブでなくなる直前 NSNotification.Name.UIApplicationWillResignActive UIApplicationWillResignActiveNotification
バックグランドになったら NSNotification.Name.UIApplicationDidEnterBackground UIApplicationDidEnterBackgroundNotification
終了する直前 NSNotification.Name.UIApplicationWillTerminate UIApplicationWillTerminateNotification

Objective-C で実装

アクティブでなくなる直前、hogehoge1 を呼び出します。 フォアグラウンドになったとき、hogehoge2 を呼び出します。

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(hogehoge1) name:UIApplicationWillResignActiveNotification object:nil];

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(hogehoge2) name:UIApplicationDidBecomeActiveNotification object:nil];

また、登録したイベントを削除します。

[[NSNotificationCenter defaultCenter] removeObserver:self];

Swift で実装

アクティブでなくなる直前、hogehoge1 を呼び出します。

バックグラウンドになったとき、hogehoge2 を呼び出します。

NotificationCenter.default.addObserver(self, selector: #selector(self.hogehoge1), name: NSNotification.Name.UIApplicationWillResignActive, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.hogehoge2), name: NSNotification.Name.UIApplicationDidBecomeActive, object: nil)

参考

Swift の第一引数がある関数を Objective-C で呼び出すとき、@objcを使う

2019-01-21

目的

Swift で第一引数がある関数を定義して、 Objective-C で呼び出すときに@objcキーワードを使う方法を試しました。

今回は、Objective-C で呼び出すときの関数名も指定するようにしました。

嵌った例

下記記事を参照してください

Swiftの第一引数がある関数をObjective-Cで呼び出すときの

解決した方法

Swift 側のコード

@objcMembers class Calc: NSObject
{
    @objc(addNew: b:) static func add(_ a:Int, b:Int) {
        print(a+b)
    }
}

Objective-C 側

[Calc addNew:2 b:3];

Swift の as でキャストする方法

2019-01-14

目的

Swift の as でキャストする方法をまとめました。

as について

クラスの型変換時に使われます

as

キャストの成功が保証されているときに利用します

as!

強制ダウンキャストするときに利用します

as?

ダウンキャストが成功するか分からないときに利用します

// as
// var a11 = a as Man // ダウンキャストはエラーが発生
var a12 = a as Human // 上位クラスへ

// as!
var a21 = a as! Man // 強制ダウンキャスト
// var a22 = a as! Woman // エラー

// as?
var a31 = a as? Woman
var a32 = a as? Man // 常に成功する

Swift、Objective-Cで辞書型をログに出力する方法

2019-01-07

目的

iPhone アプリを開発している時、辞書型のデータの中身を確認します。

Swift、Objective-Cで辞書型をログに出力する方法について書きます。

Swift で辞書型を確認する

let abc:[String: Any] = [
    "a": 99,
    "b": "ggg"
]
print(abc)

出力

["b": "ggg", "a": 99]

Objective-C で辞書型を確認する

NSDictionary *ab = [NSDictionary dictionaryWithObjectsAndKeys:
                    @"99", @"a",
                    @"ggg", @"b",
                    nil
                    ];
NSLog([NSString stringWithFormat:@"ABC: %@", [ab description]]);

出力

2018-12-02 14:34:42.115787+0900 exprement-objc[50570:4039196] ABC: {
    a = 99;
    b = ggg;
}

Objective-C はログを出力するだけでも一苦労でした。

参考

Swift、Objective-Cで辞書型をログに出力する方法

2019-01-07

目的

iPhone アプリを開発している時、辞書型のデータの中身を確認します。

Swift、Objective-Cで辞書型をログに出力する方法について書きます。

Swift で辞書型を確認する

let abc:[String: Any] = [
    "a": 99,
    "b": "ggg"
]
print(abc)

出力

["b": "ggg", "a": 99]

Objective-C で辞書型を確認する

NSDictionary *ab = [NSDictionary dictionaryWithObjectsAndKeys:
                    @"99", @"a",
                    @"ggg", @"b",
                    nil
                    ];
NSLog([NSString stringWithFormat:@"ABC: %@", [ab description]]);

出力

2018-12-02 14:34:42.115787+0900 exprement-objc[50570:4039196] ABC: {
    a = 99;
    b = ggg;
}

Objective-C はログを出力するだけでも一苦労でした。

参考

XcodeのRun Scriptを設定する方法

2019-01-06

目的

XcodeのRun Script を設定する方法について書きます。

ビルド時に環境ごとに読み込む設定ファイルを変えたい時などに利用できます。

スクリプトの用意

プロジェクトを選択し、「Build Phases」を選びます。

そこで 「Run Script」を追加します。

echo "Hello World"

今回は文字を表示するだけのスクリプトですが、設定ファイルを読み変えたりするときに利用できそうです。

参考

条件記述の分解 (リファクタリング-p238)

2018-12-24

目的

「リファクタリング」を理解するためにサンプルコードを PHP で書き換えてみました。

今回は「条件記述の分解」について書きます。

変更前

<?php

date_default_timezone_set('Asia/Tokyo');

class Dummy
{
    private $_winterRate = 0.6;
    private $_summerRate = 0.2;
    private $_winterServiceCharge = 250;

    const SUMMER_START = '2018/07/01 00:00:00';
    const SUMMER_END = '2018/08/31 23:59:59';

    public function calcCharge($quantity)
    {
        $now = time();
        if (strtotime(self::SUMMER_START) > $now ||
            strtotime(self::SUMMER_END) < $now) {
            return $quantity * $this->_winterRate * $this->_winterServiceCharge;
        }

        return $quantity * $this->_summerRate;
    }
}

$d = new Dummy();
echo $d->calcCharge(10) . "\n";

変更後

<?php

date_default_timezone_set('Asia/Tokyo');

class Dummy2
{
    private $_winterRate = 0.6;
    private $_summerRate = 0.2;
    private $_winterServiceCharge = 250;

    const SUMMER_START = '2018/07/01 00:00:00';
    const SUMMER_END = '2018/08/31 23:59:59';

    public function calcCharge($quantity)
    {
        if ($this->notSummer()) {
            return $this->winterCharge($quantity);
        }

        return $this->summerCharge($quantity);
    }

    private function notSummer()
    {
        $now = time();
        return (strtotime(self::SUMMER_START) > $now) ||
            (strtotime(self::SUMMER_END) < $now);
    }

    private function summerCharge($quantity)
    {
        return $quantity * $this->_summerRate;
    }

    private function winterCharge($quantity)
    {
        return $quantity * $this->_winterRate * $this->_winterServiceCharge;
    }
}

$d = new Dummy2();
echo $d->calcCharge(10) . "\n";

フィールドによるサブクラスの置き換え (リファクタリング-p232)

2018-12-23

目的

「リファクタリング」を理解するためにサンプルコードを PHP で書き換えてみました。

今回は「フィールドによるサブクラスの置き換え」について書きます。

「フィールドによるサブクラスの置き換え」 について

定数データを返すメソッドだけが異なるサブクラスがある。

変更前

<?php

abstract class Person
{
    abstract function isMale();
    abstract function getCode();
}

class Male extends Person
{
    public function isMale()
    {
        return true;
    }

    public function getCode()
    {
        return 'M';
    }
}

class Female extends Person
{
    public function isMale()
    {
        return false;
    }

    public function getCode()
    {
        return 'F';
    }
}

変更後

<?php

class Person2
{
    private $_isMale;
    private $_code;

    protected function __construct($isMale, $code)
    {
        $this->_isMale = $isMale;
        $this->_code = $code;
    }

    public static function createMale()
    {
        return new self(true, 'M');
    }

    public static function createFemale()
    {
        return new self(false, 'F');
    }

    public function isMale()
    {
        return $this->_isMale;
    }

    public function getCode()
    {
        return $this->_code;
    }
}

$kent = Person2::createMale();
echo (int)$kent->isMale() . "\n";
echo $kent->getCode() . "\n";

$ann = Person2::createFemale();
echo (int)$ann->isMale() . "\n";
echo $ann->getCode() . "\n";

State/Strategyによるタイプコードの置き換え (リファクタリング-p227)

2018-12-23

目的

「リファクタリング」を理解するためにサンプルコードを PHP で書き換えてみました。

今回は「State/Strategyによるタイプコードの置き換え」について書きます。

「State/Strategyによるタイプコードの置き換え」 について

クラスの振る舞いに影響するタイプコードがあるが、サブクラス化はできない。

タイプコードがそのオブジェクトの生存期間中に変化するか、サブクラス化が不都合な理由が別にあるときに適用できます。

変更前

<?php

class Employee
{
    private $_type;

    private $_monthlySalary;
    private $_commission;
    private $_bonus;

    const ENGINEER = 0;
    const SALESMAN = 1;
    const MANAGER = 2;

    public function __construct($type)
    {
        $this->_type = $type;
    }

    public function payAmount()
    {
        $this->_monthlySalary = 2000;
        $this->_commision = 1000;
        $this->_bonus = 3000;

        switch ($this->_type) {
            case self::ENGINEER:
                return $this->_monthlySalary;
            case self::SALESMAN:
                return $this->_monthlySalary + $this->_commission;
            case self::MANAGER:
                return $this->_monthlySalary + $this->_bonus;
            default:
                throw new Exception('不正な従業員');
        }
    }
}

$e1 = new Employee(2);
echo $e1->payAmount() . "\n";

変更後

<?php

abstract class EmployeeType
{
    const ENGINEER = 0;
    const SALESMAN = 1;
    const MANAGER = 2;

    abstract function getTypeCode();

    public static function newType($code)
    {
        switch ($code) {
            case self::ENGINEER:
                return new Engineer();
            case self::SALESMAN:
                return new Salesman();
            case self::MANAGER:
                return new Manager();
            default:
                throw new Exception('不正な従業員コード');
        }
    }
}

class Engineer extends EmployeeType
{
    public function getTypeCode()
    {
        return self::ENGINEER;
    }
}

class Salesman extends EmployeeType
{
    public function getTypeCode()
    {
        return self::SALESMAN;
    }
}

class Manager extends EmployeeType
{
    public function getTypeCode()
    {
        return self::MANAGER;
    }
}

class Employee2
{
    private $_type;

    private $_monthlySalary;
    private $_commission;
    private $_bonus;

    public function __construct($type)
    {
        $this->setType($type);
    }

    public function getType()
    {
        return $this->_type->getTypeCode();
    }

    public function setType($type)
    {
        $this->_type = EmployeeType::newType($type);
    }

    public function payAmount()
    {
        $this->_monthlySalary = 2000;
        $this->_commision = 1000;
        $this->_bonus = 3000;

        switch ($this->getType()) {
            case EmployeeType::ENGINEER:
                return $this->_monthlySalary;
            case EmployeeType::SALESMAN:
                return $this->_monthlySalary + $this->_commission;
            case EmployeeType::MANAGER:
                return $this->_monthlySalary + $this->_bonus;
            default:
                throw new Exception('不正な従業員');
        }
    }
}

$e2 = new Employee2(2);
echo $e2->payAmount() . "\n";