Kerasの環境をMacに構築する
最近、今更ながら機械学習の勉強をしてみようと思い、色々調べていました。
僕は行列計算などの高校数学もほとんどわからないのですが、最近はPythonでのエコシステムがかなり充実してきているようで、頑張れば簡単なもの位は作れるようになるかなと思い、1から勉強しようと思っています。
まずは、Macに環境構築するところから始めます。 機械学習のライブラリとしては、Google製のTensorFlowが有名(僕が知らないだけですが..)ですが、色々みていると、Chainer、Kerasというのが最近の人気のようです。
Chainerは、日本製とのことで日本語の資料が充実しているらしいのですが、今回はKerasを使ってみます。 理由は、GoogleのTensorFlowをバックエンドに使えるということもあり、今後も成熟が期待できそうだからです。
環境構築の方法は、TensorFlowの公式ページなど色々みてみましたが、Dockerを使ったクリーンな環境構築なども推奨されているようです。
ですが、僕自身Dockerの知識がそこまで豊富でないため、Docker周りのトラブルが出ても面倒なのでとりあえず普通にMacにインストールしてみたいと思います。
Pythonのバージョン管理ツールをインストール
brew install pyenv brew install pyenv-virtualenv
パスを通す&初期設定
PYENV_ROOT=~/.pyenv export PATH=$PATH:$PYENV_ROOT/bin eval "$(pyenv init -)" eval "$(pyenv virtualenv-init -)"
.bashrc
や.zshrc
にpyenvのパスを通します
Pythonのバージョンインストール
pyenv install anaconda3-4.3.1
- 今回は機械学習の為にPythonを使うため、
Anaconda
という計算系のライブラリがオールインワンになっているディストリビューションをインストールします。- ※ Anacondaの詳細については割愛します
virtualenvで環境を作る
conda create -n keras python=3.6.1 anaconda
※ 追記 一番はじめは以下のようにpyenv-virtualenv
で環境を作っていましたが、コンソールを切り替えた時などに上手く環境が切り替えられずconda
コマンドを使った方法に変更しました
pyenv virtualenv anaconda3-4.3.1 keras
ローカル環境用のディレクトリを作成する
mkdir keras cd keras
- keras用の作業環境を作成するためディレクトリを切ります
ローカル環境を切り替える
pyenv local anaconda3-4.3.1/envs/keras
- keras用の環境設定をローカル環境として設定します
Tenserflowをインストール
pip install tensorflow
kerasをインストール
pip install keras
その他必要なモジュール
pip install h5py
- 学習後の結果を保存するためのファイル(h5形式)を扱うライブラリ
設定ファイル
mkdir ~/.keras echo '{"epsilon": 1e-07, "floatx": "float32", "backend": "tensorflow"}' >> ~/.keras/keras.json
- backendをtensorflowにするための設定ファイルを作成します。
- ※ tensorflowがインストールされている状態だとデフォルトでtenserflowになっているようなので必要ないかも
以上で、インストールは完了です。
動作確認
試しにsampleソースを動かしてみます。
kerasでは、幾つかのサンプルソースが提供されています。
その中でも機械学習のチュートリアルでもよく出てくるMNIST
という手書き数字を認識するためのサンプルを動かしてみました。
https://github.com/fchollet/keras/blob/master/examples/mnist_mlp.py
'''Trains a simple deep NN on the MNIST dataset. Gets to 98.40% test accuracy after 20 epochs (there is *a lot* of margin for parameter tuning). 2 seconds per epoch on a K520 GPU. ''' from __future__ import print_function import keras from keras.datasets import mnist from keras.models import Sequential from keras.layers import Dense, Dropout from keras.optimizers import RMSprop batch_size = 128 num_classes = 10 epochs = 20 # the data, shuffled and split between train and test sets (x_train, y_train), (x_test, y_test) = mnist.load_data() x_train = x_train.reshape(60000, 784) x_test = x_test.reshape(10000, 784) x_train = x_train.astype('float32') x_test = x_test.astype('float32') x_train /= 255 x_test /= 255 print(x_train.shape[0], 'train samples') print(x_test.shape[0], 'test samples') # convert class vectors to binary class matrices y_train = keras.utils.to_categorical(y_train, num_classes) y_test = keras.utils.to_categorical(y_test, num_classes) model = Sequential() model.add(Dense(512, activation='relu', input_shape=(784,))) model.add(Dropout(0.2)) model.add(Dense(512, activation='relu')) model.add(Dropout(0.2)) model.add(Dense(10, activation='softmax')) model.summary() model.compile(loss='categorical_crossentropy', optimizer=RMSprop(), metrics=['accuracy']) history = model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, verbose=1, validation_data=(x_test, y_test)) score = model.evaluate(x_test, y_test, verbose=0) print('Test loss:', score[0]) print('Test accuracy:', score[1])
このソースを実行します
python mnist_mlp.py
以下が結果です。
Using TensorFlow backend. 60000 train samples 10000 test samples _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= dense_1 (Dense) (None, 512) 401920 _________________________________________________________________ dropout_1 (Dropout) (None, 512) 0 _________________________________________________________________ dense_2 (Dense) (None, 512) 262656 _________________________________________________________________ dropout_2 (Dropout) (None, 512) 0 _________________________________________________________________ dense_3 (Dense) (None, 10) 5130 ================================================================= Total params: 669,706 Trainable params: 669,706 Non-trainable params: 0 _________________________________________________________________ Train on 60000 samples, validate on 10000 samples Epoch 1/20 2017-06-22 12:47:14.203012: W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use SSE4.2 instructions, but these are available on your machine and could speed up CPU computations. 2017-06-22 12:47:14.203031: W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use AVX instructions, but these are available on your machine and could speed up CPU computations. 2017-06-22 12:47:14.203037: W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use AVX2 instructions, but these are available on your machine and could speed up CPU computations. 2017-06-22 12:47:14.203042: W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use FMA instructions, but these are available on your machine and could speed up CPU computations. 60000/60000 [==============================] - 8s - loss: 0.2422 - acc: 0.9254 - val_loss: 0.1386 - val_acc: 0.9573 Epoch 2/20 60000/60000 [==============================] - 6s - loss: 0.1014 - acc: 0.9699 - val_loss: 0.0768 - val_acc: 0.9771 Epoch 3/20 60000/60000 [==============================] - 6s - loss: 0.0753 - acc: 0.9771 - val_loss: 0.0798 - val_acc: 0.9758 Epoch 4/20 60000/60000 [==============================] - 6s - loss: 0.0615 - acc: 0.9815 - val_loss: 0.0732 - val_acc: 0.980 Epoch 5/20 60000/60000 [==============================] - 6s - loss: 0.0495 - acc: 0.9850 - val_loss: 0.0902 - val_acc: 0.9783 Epoch 6/20 60000/60000 [==============================] - 6s - loss: 0.0443 - acc: 0.9866 - val_loss: 0.0860 - val_acc: 0.9797 Epoch 7/20 60000/60000 [==============================] - 6s - loss: 0.0380 - acc: 0.9883 - val_loss: 0.0719 - val_acc: 0.9834 Epoch 8/20 60000/60000 [==============================] - 7s - loss: 0.0351 - acc: 0.9900 - val_loss: 0.0869 - val_acc: 0.9822 Epoch 9/20 60000/60000 [==============================] - 8s - loss: 0.0327 - acc: 0.9906 - val_loss: 0.0764 - val_acc: 0.9827 Epoch 10/20 60000/60000 [==============================] - 7s - loss: 0.0308 - acc: 0.9911 - val_loss: 0.0786 - val_acc: 0.9836 Epoch 11/20 60000/60000 [==============================] - 9s - loss: 0.0285 - acc: 0.9918 - val_loss: 0.0814 - val_acc: 0.9835 Epoch 12/20 60000/60000 [==============================] - 7s - loss: 0.0248 - acc: 0.9930 - val_loss: 0.0928 - val_acc: 0.9824 Epoch 13/20 60000/60000 [==============================] - 7s - loss: 0.0259 - acc: 0.9927 - val_loss: 0.1057 - val_acc: 0.9823 Epoch 14/20 60000/60000 [==============================] - 7s - loss: 0.0231 - acc: 0.9933 - val_loss: 0.1030 - val_acc: 0.9820 Epoch 15/20 60000/60000 [==============================] - 7s - loss: 0.0232 - acc: 0.9939 - val_loss: 0.1116 - val_acc: 0.9815 Epoch 16/20 60000/60000 [==============================] - 7s - loss: 0.0204 - acc: 0.9947 - val_loss: 0.1055 - val_acc: 0.9829 Epoch 17/20 60000/60000 [==============================] - 6s - loss: 0.0217 - acc: 0.9947 - val_loss: 0.1281 - val_acc: 0.9821 Epoch 18/20 60000/60000 [==============================] - 7s - loss: 0.0197 - acc: 0.9950 - val_loss: 0.1176 - val_acc: 0.9839 Epoch 19/20 60000/60000 [==============================] - 7s - loss: 0.0229 - acc: 0.9942 - val_loss: 0.1120 - val_acc: 0.9831 Epoch 20/20 60000/60000 [==============================] - 7s - loss: 0.0228 - acc: 0.9944 - val_loss: 0.1078 - val_acc: 0.9834 Test loss: 0.107835494385 Test accuracy: 0.9834
と動いているようです。
The TensorFlow library wasn't compiled to use AVX instructions, but these are available on your machine and could speed up CPU computations.
あたりの警告は、ソースからコンパイルしていないTenserFlowの場合CPUの拡張オプションが使えないのでスピードアップができないみたいなことみたいです。
とりあえず、よくわかってませんが動く環境をつくるところまでは成功しました。
ここから徐々に機械学習への理解を深めていきたいと思います。
参考
Installing TensorFlow on Mac OS X | TensorFlow
pyenvとanacondaを共存させる時のactivate衝突問題の回避策3種類 - Qiita
Python: Keras/TensorFlow の学習を CPU の拡張命令で高速化する (Mac OS X) - CUBE SUGAR CONTAINER
独自のDockerImageを作成する
Dockerでは、自分で独自のimageを作成することが可能です。 独自のdocker imageを作成する方法は主に2つあります。
① docker container commit
コマンドを使う
② Dockerfileからビルドする
今回は、①の起動中のDockerコンテナから新しいイメージを作成する方法を試してみます。
※ 実行環境は、Docker for Mac
を使っています。
※ 環境構築については過去記事のとおりです。
docker container commit
コマンドを使う
ベースイメージの準備
今回はnginxのイメージを元に独自のイメージを作成してみます。 まずは、ベースとなるnginxのimageをDocker Hubからダウンロードします。
docker image pull nginx:latest
docker image pull <イメージ名>:<タグ名>
- ※ タグ名を
latest
にすると最新のバージョンを取得
イメージを確認してみます。
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE nginx latest 46102226f2fd 4 days ago 109 MB
取得したイメージからコンテナを起動します。
docker run -d -p 80:80 --name webserver nginx
docker run -d -p <ポート> --name <コンテナ名> <イメージ名>
-d
: コンテナをバックグラウンドで起動する-p
: ポート指定、<ホストのポート>:<コンテナのポート>で割当を行う。 例: <80>:<12345> コンテナの12345ポートをホストの80ポートに割り当てる--name
: コンテナに名前を割り当てる
localhost
にアクセスして確認します。
nginxが起動してデフォルトのindex.htmlファイルが表示されていることが確認できました。
コンテナの内容を編集
dockerのコンテナにアクセスしてこのindexファイルを編集してみます。
docker exec -it webserver /bin/bash
docker exec -it <コンテナ名> <コマンド>
-i
: コマンド入力後にコンテナの標準入力をホストの標準入力と接続する-t
: コンテナ内の仮想端末と、Dockerホストの標準出力と接続する
cd /usr/share/nginx/html echo "<h1>Welcome my nginx</h1>" > index.html
localhost
に再度アクセスするとindex.htmlの内容が変更されていることが確認できます。
docker imageを作成
index.htmlを編集した状態の今のコンテナからimageを作成します。
docker container commit webserver mynginx:latest
docker container commit <コンテナ名> <イメージ名>:<タグ>
イメージを確認してみます
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE mynginx latest fa7dff65a5ba 5 seconds ago 109 MB nginx latest 46102226f2fd 4 days ago 109 MB
起動中のコンテナを削除して今作ったイメージからコンテナを起動します。
docker stop webserver docker rm webserver
docker stop <コンテナ名>
: コンテナを停止docker rm <コンテナ名>
: コンテナの削除
docker run -d -p 80:80 --name myserver mynginx
localhostにアクセスして確認します。
先程に編集した状態でイメージが起動していることを確認できました。
Docker for Macを使ってみる
現状は、Vagrantを使って開発環境を構築することが多いのですが、最近はDockerを使って開発しているという話をよく聞きます。 DockerだとマシンスペックをVMほど使用しないというのがメリットの一つらしく、素早く軽量に開発環境を整えるため役立つのかな?と思い勉強したいと思います。
Dockerのインストール
公式ページからMacアプリをダウンロードすることもできますが、 今回はHomebrew経由でインストールします。
brew cask install docker
- インストールが完了したらDocker.appを起動
- Docker appがシステムにアクセスするための許可を求められるためOKを押下してパスワードを入力
- 上記画面が表示されるようになってDockerコマンドが使えるようになっていればインストール完了です
docker --version Docker version 1.12.3, build 6b644ec
docker run -d -p 80:80 --name webserver nginx
Dockerコンテナを起動する
- Dockerのチュートリアルの通り2つのイメージを起動してみます。
hello-world
% docker run hello-world Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash Share images, automate workflows, and more with a free Docker ID: https://cloud.docker.com/ For more examples and ideas, visit: https://docs.docker.com/engine/userguide/
docker run
コマンドはdockerイメージからのコンテナを起動するコマンドです。- 上記の出力を見るとローカルにimageが存在しないときは、Docker Hubから該当するimageを探してダウンロードするようです。
nginx
% docker run -d -p 80:80 --name webserver nginx cdea6236c8862e3768b3560034c28c41dd7534a706a1e76b30a25c763962b32c
- 出力されているのは、コンテナの識別IDです。
-d
: コンテナをバックグラウンドで起動する-p
: ポート指定、<ホストのポート>:<コンテナのポート>で割当を行う。 例: <80>:<12345> コンテナの12345ポートをホストの80ポートに割り当てる--name
: コンテナに名前を割り当てる
この状態で、localhost
にブラウザでアクセスするとnginxのデフォルト起動画面が確認できます。
% docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES cdea6236c886 nginx "nginx -g 'daemon ..." 4 minutes ago Up 4 minutes 0.0.0.0:80->80/tcp, 443/tcp webserver
docker ps
で現在起動中のコンテナを確認できます。
その他のDockerコマンド
イメージの一覧
- ローカルに保存されているDocker imageを確認する
docker images
コンテナの停止
- dockerコンテナを停止する
docker stop <name or ID>
コンテナの削除
- dockerコンテナを削除する
- 同じ名前のコンテナは作成できないため一度削除する必要がある
docker rm <name or ID>
参考
Oracle Database ExpressをCentOSにインストールする
Oracle Databaseは、基本的には商用(有償)のDBMSですが無償で使えるパッケージが有るみたいなので試してみます。
環境
パッケージのダウンロード
- ダウンロードページから
Oracle Database Express Edition 11g Release 2 for Linux x64
をダウンロード ※ ダウンロードには、Oracleのアカウント登録が必要です
sudo yum install -y unzip unzip oracle-xe-11.2.0-1.0.x86_64.rpm.zip
インストール
- 必要なコマンドをインストール
sudo yum install -y glibc make gcc binutils libaio libaio-devel bc net-tools
sudo dd if=/dev/zero of=/swap bs=1M count=2048 sudo chmod 600 /swap sudo mkswap /swap sudo swapon /swap cat /proc/swaps
vi /etc/fstab
/swap swap swap defaults 0 0
sudo rpm -ivh Disk1/oracle-xe-11.2.0-1.0.x86_64.rpm
- インストール成功すると最後に
You must run '/etc/init.d/oracle-xe configure' as the root user to configure the database.
と表示されている
これはDB構成のコマンドらしいのでそのまま実行
sudo /etc/init.d/oracle-xe configure
- 対話型で設定が聞かれる
Oracle Database 11g Express Edition Configuration ------------------------------------------------- This will configure on-boot properties of Oracle Database 11g Express Edition. The following questions will determine whether the database should be starting upon system boot, the ports it will use, and the passwords that will be used for database accounts. Press <Enter> to accept the defaults. Ctrl-C will abort. // デフォルトのHTTPポート番号 Specify the HTTP port that will be used for Oracle Application Express [8080]: // オラクルのポート番号 Specify a port that will be used for the database listener [1521]: /etc/init.d/oracle-xe: line 405: netstat: command not found // SYSTEMユーザーのパスワード Specify a password to be used for database accounts. Note that the same password will be used for SYS and SYSTEM. Oracle recommends the use of different passwords for each database account. This can be done after initial configuration: Confirm the password: Do you want Oracle Database 11g Express Edition to be started on boot (y/n) [y]:y Starting Oracle Net Listener...Done Configuring database... Done Starting Oracle Database 11g Express Edition instance...Done Installation completed successfully.
DBへアクセス
- コマンドの読み込み
. /u01/app/oracle/product/11.2.0/xe/bin/oracle_env.sh
- sqlplusでアクセス
sqlplus system
- パスワードを聞かれるため、先程設定したものを入力
sqlplus system SQL*Plus: Release 11.2.0.2.0 Production on 日 3月 26 10:49:30 2017 Copyright (c) 1982, 2011, Oracle. All rights reserved. パスワードを入力してください: Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production に接続されました。 SQL>
- 正しくログインできれば設定完了
MySQLより説明が少なく少なくイメージがありますね。
さくらVPSにOSをインストールしてroot以外のUserを作成する
1.さくらVPSにOSをインストール
今回は、CentOS7
を選択
rootで接続できるか確認
ssh -p 22 root@<IPアドレス>
※さくらVPS上のコンソールからrootでログインできるかを確認してもOK
2.Chefの環境を構築
- Chef自体のもろもろの設定についての説明は割愛する
- Chefの設定は色々難しいので間違っているかもしれない…
Chefのツールのインストール
Chef Development Kitのインストール
chef gem install knife-zero
Chefのリポジトリ作成
chef generate repo <chef-repo_name>
knifeの設定ファイル作成
knife configure
- ~/.chef配下に
knife.rb
ができる
vim .chef/knife.rb
- ローカルプロジェクトの設定
local_mode true log_level :info log_location STDOUT chef_repo_dir = File.absolute_path( File.dirname(__FILE__) + "/.." ) cookbook_path ["#{chef_repo_dir}/cookbooks", "#{chef_repo_dir}/site-cookbooks"] node_path "#{chef_repo_dir}/nodes" role_path "#{chef_repo_dir}/roles"
リモートサーバーのknife zeroを初期化
knife zero bootstrap <IPアドレス> --ssh-user root --node-name reter-product
※ 途中rootのパスワードを聞かれるため、手順1で設定したパスワードを入力
- 作成が成功するとプロジェクト配下の
clients/
、nodes/
配下にリモートnodeの設定ファイルが作成される
3.ユーザーを作成する
- ユーザーの作成は、サードパーティのcookbookを使用する
- cookbookの管理にはBerkshelfを使用する
外部cookbookのインストール
vim Berksfile
site :opscode cookbook 'user'
chef exec berks vendor ./cookbooks
- userというcookbookは
LWRP
という方法でuserの作成を提供しており準じた形式で記述するだけでユーザーを簡単に作成できる
ログインユーザー用のssh-keyを作成
ssh-keygen -t rsa -b 4096 -f <ファイル名>
- 作業ユーザーのssh用のキーを作成
user作成用のcookbookの作成
cd site-cookbooks chef generate cookbook site-user
vim site-cookbooks/site-user/recipes/default.rb
user_account '<作成するユーザー名>' do action :create ssh_keys [' ssh-rsa ... '] # 作成したsshの公開鍵を指定する end
本番用のロールを作成
vim roles/initial_setting.json
{ "name": "initial_settings", "description": "This is initial recipes.", "chef_type": "role", "json_class": "Chef::Role", "default_attributes": { }, "override_attributes": { }, "run_list": [ "recipe[user]", "recipe[site-user]" ] }
- 実行するレシピをnodeファイルごとに制御するのは、大変なのでロールに分けておく
- roleのrun_listには、インストールした外部cookbookである
user
と自作したsite-user
を追加する- 実行順序はuserが先
ロールをnodeに追加
knife node run_list add <bootstrapのときに作成されたnode名> 'role[initial_settings]'
リモートサーバーに反映
knife zero converge "name:reter-production" --ssh-user root
sshでログインできるか確認
ssh <ユーザー名>@<サーバーIP> -i <sshの秘密鍵>
- ログインできていれば正しくユーザーが作成されている
作成したユーザーのSudo権限を許可
レシピをダウンロード
vim Berksfile
site :opscode cookbook 'user' cookbook 'sudo' # 追加
chef exec berks vendor ./cookbooks
環境設定のファイルを作成
chef exec knife environment create production -e vim
- ユーザー個別の設定は、環境依存のため設定ファイルを作成
sudo設定を記載
vim environments/production.json
{ "name": "production", "description":"Production User and Parmission", "chef_type": "environment", "json_class": "Chef::Environment", "default_attributes": {}, "override_attributes": { "authorization": { "sudo": { "users": ["<sudo権限を与えるユーザー>"], "passwordless": "true" } } } }
nodeファイルを編集して環境をproductionに変更する
chef exec knife node edit reter-production -e vim
設定を反映
knife zero converge "name:<ロール名>" --ssh-user root
sudoを実行できるか確認
ssh <ユーザー名>@<サーバーIP> -i <sshの秘密鍵>
sudo vim /etc/sudoers
- 設定したuserにsudo設定がされていればOK
【iOS, swift】swiftコーディング規約
※ Swift 2.3をベースに記載
自分がswiftを書くときのコーディング規約を記載します。
クラス
- Pascal記法 (大文字で始まる) で記述する
// ◯ class ViewController: UIViewController { } // ☓ snake case class view_controller: UIViewController { ・・・ }
継承
する時にクラス名の後ろにつける:
は:の後ろにスペースを入れる
// ◯ class ViewController: UIViewController { } // ☓ class view_controller:UIViewController { }
メソッド
- Camel記法(小文字始まり)で記述する(
hogeFuga
) - メソッド名は動詞を使う
;
は付けない{
の行は改行しない。前にスペースを入れる。->
の前後はスペースを入れる
// ◯ func getName() -> Strig { return "name" } // ☓ name snake func getName() -> Strig { return "name" } // ☓ break func getName() -> Strig { return "name" } // ☓ space func getName()->Strig { return "name" }
変数・プロパティ(保持型・計算型)
- Camel記法(小文字始まり)で記述する(
hogeFuga
) - 行末に
;
は付けない - privateな保持型プロパティは
_
から始める(_hogeFuga
) - interlな保持型プロパティは
internal
を省略する- 理由: 基本的にスコープは厳格にすべきである。
- しかし
private
スコープはテストファイルから参照できない。 - テストを書くことの方が重要のため基本的に
internal
であることを許可する。 internal
がデフォルトであるため、冗長を削除するため省略して良しとする。
- 基本的に
public
は使用しない- 理由: 同じモジュール内であれば参照可能なためPublicは必要ない
- ※ APIを定義する場合は必要
計算型プロパティ
のgetがある場合はprivate
でOK
class Sample { // ◯ var userName: Int; private var _userMessage: String; func hoge() -> Int { let age = 10 return age } private var _inSpeed: Double = 0 var speed: Double { get { return self._inSpeed + 10; } set(speed) { self._inSpeed = speed } } // ☓ Pascal var UserName: String; // ☓ not `_` private var userLevel: Int; }
- storybord(or xib)上で強参照する変数(ViewController.viewが保持するなど)は
@IBOutlet weak var
で宣言する
// ◯ @IBOutlet weak var clickHogeButton: UIBarButtonItem! // ☓ @IBOutlet var clickHogeButton: UIBarButtonItem!
- 読み取り専用のプロパティと添字付けのgetterは暗黙的にする
- 可能な限り、読み取り専用のプロパティと添字付けでは
get
キーワードを省略する - 理由: 意図と意味が明確だから。コードも少なくて済む。
// ◯ var myGreatProperty: Int { return 4 } subscript(index: Int) -> T { return objects[index] } // ☓ var myGreatProperty: Int { get { return 4 } } subscript(index: Int) -> T { get { return objects[index] } }
enum
// ◯ enum CustomResult { case Success, case Error } // ☓ upper case enum CustomResult { case SUCCESS, ERROR } // ☓ Case is not omitted enum CustomResult { case Success, Error }
if
- 判定式に
()
は付けない {
の前には改行は入れない
// ◯ let x = 1 if x == 1 { print("") } // ☓ let x = 1 if (x == 1) { print("") }
for
for-in
を使用する{
の前には改行は入れない- cの構文
for(let i; i < 10; i++)
は使わない(非推奨になっている)
// ◯ var sum: Int = 0 for i in 1...10 { sum += i } // ☓ var sum: Int = 0 for (var i = 1; i <= 10; i += 1) { sum += i }
switch
{
の前には改行は入れないswitch
とcase
の左は揃える
// ◯ let c: Int = 1 switch c { case 1: print("") } // ☓ let c: Int = 1 switch c { case 1: print("") }
可能な限りvar
宣言よりもlet
宣言を使う
- 理由:
let
は値が変わらないことを保証するためより安全で明確なコードになる
1行の文字数
- 努力目標:80文字
- 最大:100文字
識別子に型を指定する時は、常に識別子のすぐ後ろにコロンを置き、空白を一つあけて型名を書く
// ◯ class MyClass: SuperClass { ... } let myConst: Int = 2 func myFunc(type: Int) -> String { ... } // ☓ class MyClass:SuperClass { ... } let myConst:Int = 2 func myFunc(type:Int) -> String { ... }
明示的なself
参照は必要な時だけ
self
の持つプロパティやメソッドへアクセスする時、デフォルトではself
への参照は省く- 理由: クロージャにおける
self
のキャプチャリングが目立つようになる。その他の場所における冗長さが無くなるため。
class MyClass { var hoge: Int // ◯ func myFunc() { hoge = 1234 } var myClosure: () -> () { return { self.hoge } } // ☓ func myFunc() { self.hoge = 1234 } }