Swift でジェネリック型のクランプをする

クランプ(Clamp)とは、ある値が任意の範囲になるように調整することをいう。

たとえば、値を 0 〜 10 の値にしたければ、以下のようなコードを書く。

if x < 0 {
  x = 0
}

if x > 10 {
  x = 10
}

ただし、必要な箇所でその都度、上のようなコードを書くと煩雑なので、これを関数化すると便利だ。

対象の型を特定しないようにジェネリック(Generic)にして関数化すると下のようになった。

static func clamp<T: Comparable>(_ val: T, min: T, max: T) -> T {
  if val < min {
    return min
  }

  if val > max {
    return max
  }

  return val
}

Travis CI で CocoaPods を使用したプロジェクトがビルド失敗する

はじめに

Travis CI で CocoaPods を使用したプロジェクトのビルドが失敗したため、調べたことをメモ。

リファレンス

Travis CI のドキュメント この中の Building an Objective-C or Swift Project - Travis CI のセクションをみる。

抜粋

リファレンスに書いてあることで重要なところを抜粋する

  1. Travis CI は、デフォルトは pod install コマンドで依存関係を解決する
    • しかしこれは、プロジェクトのルートディレクトリに Podfile が検出されたときにのみ実行される
    • Podfile がルートディレクトリ以外にある場合は、.travis.yml に podfile 設定を書く
      • .travis.yml 内に podfile: path/to/Podfile を記載する。注意点は Podfile のあるディレクトリのパスではなく、Podfile のファイル名を含めたパスを指定する必要がある。
  2. また、 Pods ディレクトリがあり .Podfile.lock に変更がない場合は、pod install は実行されない
  3. ルートディレクトリに Gemfile がある場合は pod install は実行されず、代わりに Bundler が pod のラッパーとして使用されます。
    • bundle exec pod install

通常 CocoaPods を扱う場合は 1. と 2. が気をつけるところかな

Swift を Docker 上の Linux(Ubuntu) で動作させる

資料

手順

Docker 側

1. Docker をインストール
$ brew cask install docker
2. Ubuntu のイメージを得る
$ docker pull ubuntu
3. Ubuntu コンテナを作成
$ docker run --privileged -it ubuntu /bin/bash
4. コンテナ開始
$ docker start <ID>
5. コンテナにアタッチ
$ docker attach <ID>

Ubuntu

1. パッケージを更新
# apt update
2. Swift に必要なパッケージを得る
# apt-get install git cmake ninja-build clang python uuid-dev libicu-dev icu-devtools libbsd-dev libedit-dev libxml2-dev libsqlite3-dev swig libpython-dev libncurses5-dev pkg-config libblocksruntime-dev libcurl4-openssl-dev systemtap-sdt-dev tzdata rsync
3. Swift をダウンロード
# cd /opt/
# apt-get install wget
# wget https://swift.org/builds/swift-5.0-release/ubuntu1604/swift-5.0-RELEASE/swift-5.0-RELEASE-ubuntu16.04.tar.gz
4. Unzip
# tar xvfz swift-5.0-RELEASE-ubuntu16.04.tar.gz
# mv swift-5.0-RELEASE-ubuntu16.04 swift
5. パス設定
# export PATH=/opt/swift/usr/bin:"${PATH}"
6. テスト
# swift -version
Swift version 5.0 (swift-5.0-RELEASE)
Target: x86_64-unknown-linux-gnu

メモ

ホストのファイルをコンテナにコピー

$ docker cp file.cnf <ID>:/etc/file.cnf
$ docker cp dir <ID>:/etc/dir

CocoaPods にライブラリを登録する

この記事は

  • CocoaPods へライブラリを登録する方法をまとめる。

登録の方法

1. podspec ファイルを作成する

$ pod spec create MyLib

2. podspec ファイルを編集する

  • 以下、サンプルを載せる
  • Podspec ファイルの構文リファレンスについて詳しくは Podspec Syntax Reference を参照すること
Pod::Spec.new do |spec|

  # ―――  メタデータ  ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  # 名前、バージョン、概要など記載
  spec.name         = "MyLib"
  spec.version      = "1.0.0"
  spec.summary      = "This is MyLib."

  # 説明
  # << -DESC から DESC までが使われる。
  spec.description  = <<-DESC
                   This is MyLib Description.
                   DESC

  # ホームページ
  spec.homepage     = "https://github.com/daisuke-t-jp/MyLib"

  # スクリーンショット
  spec.screenshots  = "https://raw.githubusercontent.com/daisuke-t-jp/MyLib/master/images/header.png"


  # ―――  ライセンス  ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  spec.license      = { :type => "MIT", :file => "LICENSE" }


  # ――― 作者  ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  spec.author       = { "daisuke-t-jp" => "daisuke.t.jp@gmail.com" }


  # ――― プラットフォーム指定 ――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  spec.ios.deployment_target = "10.0"
  spec.osx.deployment_target = "10.12"
  spec.tvos.deployment_target = "12.0"


  # ――― ソース関連―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  # Git リポジトリとタグを指定する
  spec.source       = { :git => "https://github.com/daisuke-t-jp/MyLib.git", :tag => "#{spec.version}" }

  spec.source_files  = "Sources/MyLib/*.{swift}"


  # ――― プロジェクト設定 ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  spec.swift_version = "5.0"
  spec.requires_arc = true

end

注意点

  • source_files には info.plist を含めないようにする

3. リントを実行する

$ pod lib lint

エラーや警告の内容をチェックする

4. CocoaPods にアカウントを登録する

ライブラリ(リポジトリ)ごとに一度で良い

$ pod trunk register mail@addr 'Account name'

5. CocoaPods にライブラリをプッシュする

$ pod trunk push MyLib.podspec

もし、警告によりプッシュが失敗してしまい、かつその警告を無視してプッシュしたい場合は --allow-warnings オプションをつける

$ pod trunk push MyLib.podspec --allow-warnings

これで完了

6. ライブラリの更新をプッシュする時は...

  • Podspec を必要に応じて更新して(バージョンの記載部分など)
  • リントしてから
  • プッシュをする

おわり

macOS のキャッシュや履歴を削除する

macOS のいろいろなキャッシュや履歴を削除する方法をメモする。必要に応じて sudo で実行する。

ターミナル(termial.app) の履歴を削除する

$ history -c
$ rm -f ~/.bash_history

このあと現在開いてあるターミナルアプリを終了させる必要あり。

キャッシュを削除する

$ rm -rf /System/Library/Caches/*
$ rm -rf /Library/Caches/*
$ rm -rf ~/Library/Caches/*

これでシステムとユーザ領域のキャッシュを削除できる

スポットライトの検索履歴を削除する

$ mdutil -i off /
$ rm -rf /.Spotlight-V100/
$ mdutil -E -i on /

Xcode 関連の設定や履歴を削除する

##### シミュレータ #####
# すべてのシミュレータをリセット
$ xcrun simctl erase all


##### Xcode #####
# アーカイブ
$ rm -rf ~/Library/Developer/Xcode/DerivedData/*
$ rm -rf ~/Library/Developer/Xcode/Archives/*

# Instruments
$ rm -f ~/Library/Preferences/com.apple.dt.Instruments.plist

# Xcode の設定 plist を削除する
$ rm -f ~/Library/Preferences/com.apple.dt.Xcode.plist

# Xcode の設定 plist 内のキーを指定して個別に項目を削除する
# どの項目を消すのかは plist を見て確認しながら...
# とりあえず以下が削除対象として良さそう
$ plutil -remove "DVTTextCompletionRecentCompletions" ~/Library/Preferences/com.apple.dt.Xcode.plist
$ plutil -remove "IDESourceControlRecentsFavoritesRepositoriesUserDefaultsKey" ~/Library/Preferences/com.apple.dt.Xcode.plist
$ plutil -remove "IDEDefaultPrimaryEditorFrameSizeForPaths" ~/Library/Preferences/com.apple.dt.Xcode.plist
$ plutil -remove "NSNavLastRootDirectory" ~/Library/Preferences/com.apple.dt.Xcode.plist

CocoaPods のリポジトリを削除する

$ rm -rf ~/.cocoapods/*

ゴミ箱を空にする

$ rm -rf ~/.Trash/*

再起動/シャットダウン

いろいろ削除したあとは OS を一旦終了させた方が良い

$ shutdown -r now  # 再起動
$ shutdown -h now # シャットダウン

おわり

macOS フォルダ内のファイルのエンコーディングを一覧表示する

フォルダ内にある Xcode 関連ファイル

  • h
  • m
  • mm
  • swift
  • txt
  • md
  • plist
  • strings

エンコーディング一覧を見たい場合は find コマンドでできる

# 現在のパスから開始する
$ find -E . -type f -iregex ".*\.(h|m|mm|swift|txt|md|plist|strings)" -exec file --mime {} \;

# 指定パスから開始する
$ find -E <PATH> -type f -iregex ".*\.(h|m|mm|swift|txt|md|plist|strings)" -exec file --mime {} \;

Swift で Mach から CPU 負荷、メモリ使用量を得るフレームワーク Mach-Swift

はじめに

iOS / macOS にて CPU 負荷、メモリ使用量を得るために Mach を使用する方法があります。
ただ、Mach の関数を直接使用するとポインタの扱いが手間なので、そのあたりを吸収した Swift フレームワークを作成しました。

github.com

使い方は以下です。

インストール

CocoaPods

Podfile を作成する

platform :ios, '10.0'    # iOS の場合
platform :osx, '10.12'   # macOS の場合
use_frameworks!

target 'YOUR-TARGET' do
    pod 'Mach-Swift', :git => 'https://github.com/daisuke-t-jp/Mach-Swift.git'
end

インストール

$ pod install

サンプルコード

ホスト(OS)

仮想メモリ情報

import Mach_Swift

// host_statistics(HOST_VM_INFO) 相当
let vm = Mach.Host.Statistics.vmInfo()
print("- freeSize: \(vm.freeSize)") // 空きサイズ (byte)
print("- activeSize: \(vm.activeSize)") // アクティブサイズ (byte)
print("- inactiveSize: \(vm.inactiveSize)") // 非アクティブサイズ (byte)
print("- wireSize: \(vm.wireSize)") // 固定サイズ (byte)
- freeSize: 130482176
- activeSize: 1765789696
- inactiveSize: 1649594368
- wireSize: 2495418368

CPU 負荷

import Mach_Swift

// host_statistics(HOST_CPU_LOAD_INFO) 相当
let cpuLoadInfo = Mach.Host.Statistics.cpuLoadInfo()
print("- userTick: \(cpuLoadInfo.userTick)")        // ユーザチック
print("- systemTick: \(cpuLoadInfo.systemTick)")    // システムチック
print("- idleTick: \(cpuLoadInfo.idleTick)")        // アイドルチック
print("- niceTick: \(cpuLoadInfo.niceTick)")        // ナイスチック
- userTick: 785470
- systemTick: 503253
- idleTick: 4632473
- niceTick: 0

基本情報

import Mach_Swift

// host_info(HOST_BASIC_INFO) 相当
let basicInfo = Mach.Host.Info.basicInfo()
print("- maxCPUs: \(basicInfo.maxCPUs)")    // CPU 総数
print("- availCPUs: \(basicInfo.availCPUs)")    // 利用可能 CPU 数
print("- memorySize: \(basicInfo.memorySize)")
print("- cpuType: \(basicInfo.cpuType)")
print("- cpuSubType: \(basicInfo.cpuSubType)")
print("- cpuThreadType: \(basicInfo.cpuThreadType)")
print("- physicalCPU: \(basicInfo.physicalCPU)")
print("- physicalCPUMax: \(basicInfo.physicalCPUMax)")
print("- logicalCPU: \(basicInfo.logicalCPU)")
print("- logicalCPUMax: \(basicInfo.logicalCPUMax)")
print("- maxMem: \(basicInfo.maxMem)")  // byte size
- maxCPUs: 4
- availCPUs: 4
- memorySize: 2147483648
- cpuType: 7
- cpuSubType: 8
- cpuThreadType: 1
- physicalCPU: 2
- physicalCPUMax: 2
- logicalCPU: 4
- logicalCPUMax: 4
- maxMem: 8589934592

プロセッサ(コア)

import Mach_Swift

// host_processor_info() 相当
let array = Mach.Host.Processor.cpuLoadInfoArray()
for i in 0..<array.count {
    let cpu = array[i]
    print("- Core No.\(i)")
    print("    - userTick: \(cpu.userTick)")
    print("    - systemTick: \(cpu.systemTick)")
    print("    - idleTick: \(cpu.idleTick)")
    print("    - niceTick: \(cpu.niceTick)")
    print("")
}
- Core No.0
    - userTick: 257206
    - systemTick: 186605
    - idleTick: 1036690
    - niceTick: 0

- Core No.1
    - userTick: 144763
    - systemTick: 87848
    - idleTick: 1247622
    - niceTick: 0

- Core No.2
    - userTick: 251769
    - systemTick: 155100
    - idleTick: 1073364
    - niceTick: 0

- Core No.3
    - userTick: 131732
    - systemTick: 73700
    - idleTick: 1274800
    - niceTick: 0

タスク(アプリ、プロセス)

基本情報

import Mach_Swift

// task_info() 相当
let basicInfo = Mach.Task.Info.basicInfo()
print("- virtualSize: \(basicInfo.virtualSize)")    // 仮想メモリサイズ (byte)
print("- residentSize: \(basicInfo.residentSize)")  // 実メモリサイズ(byte)
print("- residentSizeMax: \(basicInfo.residentSizeMax)")    // 実メモリ最大サイズ(byte)
print("- userTime: \(basicInfo.userTime)")      // ユーザ時間
print("- systemTime: \(basicInfo.systemTime)")      // システム時間
print("- policy: \(basicInfo.policy)")
print("- suspendCount: \(basicInfo.suspendCount)")
- virtualSize: 5425922048
- residentSize: 78155776
- residentSizeMax: 78155776
- userTime: 0.000426
- systemTime: 0.003031
- policy: 1
- suspendCount: 0

スレッド基本情報

import Mach_Swift

// task_threads() 相当
let array = Mach.Task.Thread.basicInfoArray()
for i in 0..<array.count {
    let thread = array[i]
    print("- Thread No.\(i)")
    print(String.init(format:"    - userTime: %.2f", thread.userTime))
    print(String.init(format:"    - systemTime: %.2f", thread.systemTime))
    print("    - cpuUsage: \(thread.cpuUsage)")
    print("    - policy: \(thread.policy)")
    print("    - runState: \(thread.runState)")
    print("    - flags: \(thread.flags)")
    print("    - suspendCount: \(thread.suspendCount)")
    print("    - sleepTime: \(thread.sleepTime)")
    print(String.init(format:"    - sleepTime: %.2f", thread.sleepTime))
    print("")
}
- Thread No.0
    - userTime: 0.24
    - systemTime: 0.93
    - cpuUsage: 626
    - policy: 1
    - runState: 1
    - flags: Flag(rawValue: 0)
    - suspendCount: 0
    - sleepTime: 0.0
    - sleepTime: 0.00

- Thread No.1
    - userTime: 0.01
    - systemTime: 0.01
    - cpuUsage: 23
    - policy: 1
    - runState: 3
    - flags: Flag(rawValue: 1)
    - suspendCount: 0
    - sleepTime: 0.0
    - sleepTime: 0.00

- Thread No.2
    - userTime: 0.00
    - systemTime: 0.00
    - cpuUsage: 6
    - policy: 1
    - runState: 3
    - flags: Flag(rawValue: 1)
    - suspendCount: 0
    - sleepTime: 0.0
    - sleepTime: 0.00

- Thread No.3
    - userTime: 0.00
    - systemTime: 0.00
    - cpuUsage: 0
    - policy: 1
    - runState: 3
    - flags: Flag(rawValue: 1)
    - suspendCount: 0
    - sleepTime: 0.0
    - sleepTime: 0.00

- Thread No.4
    - userTime: 0.00
    - systemTime: 0.00
    - cpuUsage: 4
    - policy: 1
    - runState: 3
    - flags: Flag(rawValue: 1)
    - suspendCount: 0
    - sleepTime: 0.0
    - sleepTime: 0.00

- Thread No.5
    - userTime: 0.00
    - systemTime: 0.01
    - cpuUsage: 12
    - policy: 1
    - runState: 3
    - flags: Flag(rawValue: 1)
    - suspendCount: 0
    - sleepTime: 0.0
    - sleepTime: 0.00

おわりに

Mach-Swift で取得できる情報を元に負荷をビュー表示するフレームワークもあります。

github.com