自宅用Macを新調した話
最近自宅用のMacを新調しました。
というのも先代のMacはかれこれ6年ちょっと使っていたもので、ここ1〜2年は大分動作が重く、Xcodeなどの開発環境は起動するのも億劫になるほど…。
そのため、今回は開発環境が快適に使えることを基準にカスタマイズしたところ、無事軽快に動くようになりました!これから開発用マシンを購入する方のご参考までに。
- マシン:(旧)IMac2011年モデル→(新)iMac 2017年モデル
- メモリ:(旧)4GB→(新)16GB
- ストレージ:(旧)HDD512GB→(新)SSD 512GB
なかなかの出費ではありましたが、これで技術的に気になっていたことを色々試せるので嬉しいです。技術を磨いてお仕事に繋げたいと思います。業務では未だにObjective-CやJavaがメインですが、最近Swift4やKotlinなどが気になっています。
旧Macからのデータ移行は、TimeMachineを使わずに必要なデータだけ外付けHDDに入れて移動しました。TimeMachineは楽ですが、余計なファイルや設定を引き継いでしまう可能性があるということで。
下記のページを参考に、一旦新しいMacとして初期設定した後、書類、iTunes、写真などを移行しました。
Mac自体は新しいものとして設定した上で、特定のアプリケーションだけTimeMachineから復元するということもできるようです。
【PHP】PHPからSQLを実行する
PHPからPDO(PHP Data Object)を使用してSQLを実行する手順です。
お決まりの手順ですが、たまにやると手順が抜けたり順番を忘れたりするので、まとめておきます。
トランザクションなしの場合
データベースからデータを検索するサンプルです。
// DB接続 try { // ①データベースハンドラ作成 $pdo = new PDO('mysql:host=localhost;dbname=sampledb;charset=utf8', 'username', 'password'); // ②エラー属性設定 $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // 例外を発生させる } catch (PDOException $Exception) { die('接続エラー :' . $Exception->getMessage()); } // 処理実行 try { // ③SQL作成 $sql = "select * from member"; // ④ステートメントハンドラ作成、処理を実行 $smth = $pdo->query($sql); // 結果を表示 print "登録されているデータは全部で".$smth->rowCount()."件です。<br>"; } catch (PDOException $Exception) { print "エラー:" . $Exception->getMessage(); }
①データベースハンドラ作成
DSN(Data Source Name)を指定してデータベースに接続します。
DSNは以下のような構文で、データベースの種類によって指定できる項目が若干変わります。
(サンプルはMySQLの場合です)
<DSN接頭辞>:host=<ホスト名>;dbname=<データベース名>;charset=<文字コード>
②エラー属性設定
エラーが発生した際にtry catchで例外を検出できるように設定します。
トランザクションありの場合
トランザクション処理を利用することで、処理実行中は他のユーザーのデータベース更新処理がブロックされます。
また、処理に失敗した場合、ロールバック処理で元の状態に戻すことができます。
データの新規登録、更新、削除などではトランザクション処理を利用すべきでしょう。
トランザクション処理を利用する場合は、処理を$pdo->beginTransactionと$pdo->commit()で囲みます。
以下は、データを新規登録するサンプルです。
// DB接続 try { // ①データベースハンドラ作成 $pdo = new PDO('mysql:host=localhost;dbname=sampledb;charset=utf8', 'username', 'password'); // ②エラー属性設定 $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // 例外を発生させる $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); // プリペアドステートメントを利用 } catch (PDOException $Exception) { die('接続エラー :' . $Exception->getMessage()); } // 処理実行 try { // ③トランザクション開始 $pdo->beginTransaction(); // ④SQL、ステートメントハンドラ作成 $sql = "insert into member (username, password, register_date) values(:username, :password, now())"; $smth = $pdo->prepare($sql); // ⑤データをバインド $smth->bindValue(':username', 'test@example.com'); $smth->bindValue(':password', 'test'); // ⑥処理を実行 $smth->execute(); // ⑦変更を確定 $pdo->commit(); // 結果を表示 print "データを".$smth->rowCount()."件挿入しました。<br>"; } catch (PDOException $Exception) { // ⑧元の状態に戻す $pdo->rollBack(); print "エラー:" . $Exception->getMessage(); }
①データベースハンドラ作成
同上。
②エラー属性設定
例外発生の設定に加え、プリペアドステートメント利用の設定をします。
④SQL、ステートメントハンドラ作成
初期値を指定してデータを新規登録するSQLを記述します。
最初の()内はカラム名、後の()は初期値です。
username, passwordはログインフォームなどでユーザの入力値を使うことを想定しています。
この場合は、名前付きプレースホルダ(:username, :password)を指定し、後で変数と関連付けます。
register_dateは現在時刻を使うことを想定しています。
このようにメソッドで取得できる値や決め打ちの値を使う場合は、SQL中に直接書けます。
⑤データをバインド
④の名前付きプレースホルダに変数の値を結びつけます。
⑥処理を実行
準備ができたので、SQLを実行します。
⑦変更を確定
変更を確定します。
⑧元の状態に戻す
処理の途中でエラーが発生した場合、$pdo->rollBack()を呼んで処理を元に戻します。
【PHP】データを次の画面以降に引き継ぐ方法
画面には表示しない内部データを次の画面に引き継ぎたいとき、いくつかある方法のサンプルコードや特徴、使い分け方について勉強したことをまとめます。
まだざっくりとしか調べていないので、間違っているところがあればご指摘いただければ幸いです。
1. hidden
使い方
// 渡し方 <form name="form1" method="post" action="confirm.php"> <p> <label for="name">タイトル:</label><input type="text" name="title"> </p> <p> <label for="name">本文:</label><textarea name="body_text" cols="30" rows="5"></textarea> </p> <input type="hidden" name="login_id" value="abc123"> <p> <input type="submit" value="確認"> </p> </form> // 受け取り方 <?php print "<p>"; print "タイトル:".$_POST["title"]; print "</p>"; print "<p>"; print "本文:".nl2br($_POST["body_text"]); print "</p>"; print "<p>"; print "ログインID:".$_POST["login_id"]; print "</p>"; ?>
メリット
・セッションなどの知識がなくても簡単に利用できる
2.cookie(クッキー)
使い方
// 渡し方 <?php // クッキーを送信(有効期限30日) setcookie("login_id", "id00001", time() + 60 * 60 * 24 * 30); ?> // 受け取り方 <?php if (isset($_COOKIE["login_id"])) { print "<p>"; print "ログインID:".$_COOKIE["login_id"]; print "</p>"; } ?> // 消し方 <?php // 有効期限に現在よりも前の時間を設定 setcookie("login_id", "", time() - 60); ?>
メリット
・一度セットした値を複数画面で使える
デメリット
・クライアント側に保存されるため、改竄が可能である
・一つのドメインで保存できる数に上限がある(上限数はブラウザによって異なる)
⇒利用者の識別情報、セッションIDなど、クライアント側で保存しておきたい情報に使える
3.session(セッション)
使い方
// 渡し方 <?php session_start(); // 有効期限30日 session_cache_expire(60 * 24 * 30); $_SESSION["login_id"] = "id00001"; ?> // 受け取り方 <?php session_start(); if (isset($_SESSION["login_id"])) { print "<p>"; print "ログインID:".$_SESSION["login_id"]; print "</p>"; } ?> // 消し方 <?php session_start(); // セッション変数をすべて削除 session_unset(); // セッションIDおよびデータを破棄 session_destroy(); ?>
メリット
・一度セットした値を複数画面で使える
・サーバ側で保存するため、データ改竄の心配がない
デメリット
・サーバ上にセッションファイルを保存するため、適切な権限の設定が必要=やや知識が必要
⇒ログインにより取得したユーザ情報、ショッピングサイトの買い物かごデータなどに使える
(接続から切断までの一連の通信がセッションの典型例としてよく挙げられていることから、
クッキーよりも短期間、一時的なものという印象を受けました)
大雑把な使い分けとしては、
- フォームで次の画面まで引き継ぎたい&ユーザに見えても構わない情報→hidden
- 偽装されてはいけない情報→session
- 偽装されても問題ない情報、接続時にサーバへ送りたい情報→cookie
という感じでしょうか。
Dockerで PHP+MySQLの環境構築
2018年になりました。今年はスマホアプリだけでなくWeb開発にも挑戦していきたいと思います。
ということで手始めに『PHP+MySQLマスターブック』でPHPを勉強することにしました。
book.mynavi.jp
PHP5.4&MySQL5.5対応と少しバージョンが古いですが、ログイン機能を持つ会員管理システムが作れる、Smarty(テンプレートエンジン)にも触れているということで、一冊終わる頃には実用的な知識が身につきそうです。
同書ではXAMMPの使用を推奨していますが、今回はDockerを使って環境構築しました。以下、その手順です。
Dockerとは
Dockerについては以下のサイトがわかりやすいです。本記事ではDockerのインストールは済んでいることを前提とします。
employment.en-japan.com
1.コンテナの準備
CentOS最新版のイメージを取得します。
$ docker pull centos
centosイメージからコンテナを作成・起動します。
$ docker run --privileged -it -d -p 8080:80 -p 3306:3306 -v "/Users/yourname/htdocs/:/var/www/html/" --name MySqlTest centos /sbin/init
色々オプションがついていますが、それぞれの意味は次の通りです。
- --privileged:特権モードを指定。systemctlコマンドを使用するために付加
- -it:コンテナ内で操作できる
- -d :コンテナの実行をバックグラウンドで行う
- -p 8080:80:ローカルマシンの8080番ポートとコンテナの80番ポートを紐付ける。これによりローカルマシンのWebブラウザから"http://localhost:8080/"でWebページにアクセス可能となる
- -p 3306:3306:同上。3306番ポートはMySQLのポート番号
- -v "/Users/yourname/htdocs/:/var/www/html/":ローカルマシンの任意のディレクトリ(htdocs)とコンテナのドキュメントルート(/var/www/html/)を紐付ける
- --name MySqlTest:コンテナの名前
- /sbin/init :systemctlコマンドによるOS起動時のサービス自動起動のために付加
以下のコマンドでMySqlTestが表示されれば、正しくコンテナを起動できています。
$ docker ps
作成したコンテナにログインします。
$ docker exec -it MySqlTest /bin/bash
タイムゾーンを日本時間に変更します。
# timedatectl set-timezone Asia/Tokyo # timedatectl
2.Apacheのインストール
Apache最新版をインストールします。
# yum install -y httpd
httpd.confを編集します。今回は開発用に必要な部分しか設定していません。
念のためオリジナルを複製しておきます。
# cp /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf.bak # vi /etc/httpd/conf/httpd.conf <Directory "/var/www/html"> # ファイル一覧を非表示 Options -Indexes +FollowSymLinks # .htaccessを利用するため AllowOverride All Require all granted </Directory> <IfModule dir_module> # index.phpを省略可 DirectoryIndex index.php index.html </IfModule>
Apacheを起動します。また、OS再起動時に自動起動するように設定しておきます。
# systemctl start httpd.service # systemctl enable httpd.service
webブラウザから"http://localhost:8080"にアクセスし、Apacheのデフォルトページが表示されればOKです。
3.PHPのインストール
PHP5.4とその他必要なライブラリをインストールします。
CentOS7のPHPは標準で5.4なので特にバージョンは指定しなくて大丈夫です。
# yum install -y php php-mbstring php-mysql php-mcrypt
php.iniを編集します。
# cp /etc/php.ini /etc/php.ini.bak # vi /etc/php.ini default_charset = "UTF-8" date.timezone = "Asia/Tokyo" mbstring.language = Japanese mbstring.internal_encoding = UTF-8 mbstring.http_input = UTF-8 mbstring.http_output = pass mbstring.encoding_translation = On mbstring.substitute_character = none;
php.iniを保存したら、変更を反映するためApacheを再起動します。
# systemctl restart httpd.service
以下のコードをphpinfo.phpという名前でドキュメントルート(本記事だと"/Users/yourname/htdocs/")に保存します。
<?php phpinfo(); ?>
webブラウザから"http://localhost:8080/phpinfo.php"にアクセスし、PHPに関する情報が表示されればOKです。
4.MySQLのインストール
CentOS7には標準でMariaDBがインストールされていますので、競合を防止するために削除します。
# yum remove -y mariadb-libs # rm -rf /var/lib/mysql/
リポジトリを追加します。
# yum install -y http://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm
インストールしたリポジトリを見るとMySQL5.7がenableになっているので、5.5に変更します。
# yum repolist all | grep mysql mysql-cluster-7.5-community/x86_64 MySQL Cluster 7.5 Community disabled mysql-cluster-7.5-community-source MySQL Cluster 7.5 Community - S disabled mysql-cluster-7.6-community/x86_64 MySQL Cluster 7.6 Community disabled mysql-cluster-7.6-community-source MySQL Cluster 7.6 Community - S disabled mysql-connectors-community/x86_64 MySQL Connectors Community enabled: 42 mysql-connectors-community-source MySQL Connectors Community - So disabled mysql-tools-community/x86_64 MySQL Tools Community enabled: 55 mysql-tools-community-source MySQL Tools Community - Source disabled mysql-tools-preview/x86_64 MySQL Tools Preview disabled mysql-tools-preview-source MySQL Tools Preview - Source disabled mysql55-community/x86_64 MySQL 5.5 Community Server disabled mysql55-community-source MySQL 5.5 Community Server - So disabled mysql56-community/x86_64 MySQL 5.6 Community Server disabled mysql56-community-source MySQL 5.6 Community Server - So disabled mysql57-community/x86_64 MySQL 5.7 Community Server enabled: 227 mysql57-community-source MySQL 5.7 Community Server - So disabled mysql80-community/x86_64 MySQL 8.0 Community Server disabled mysql80-community-source MySQL 8.0 Community Server - So disabled
# yum install yum-utils # yum-config-manager --disable mysql57-community # yum-config-manager --enable mysql55-community
これでようやくMySQL5.5をインストールできます。
# yum install -y mysql mysql-devel mysql-server
インストールが終わったら、MySQLのバージョンが5.5になっているのを確認します。
# mysqld --version
# systemctl start mysqld.service # systemctl enable mysqld.service
rootのパスワード設定などの初期設定を行います。
# mysql_secure_installation Enter current password for root (enter for none): [そのままEnter] // rootのパスワード設定 Set root password? [Y/n] Y New password: [パスワードを入力] Re-enter new password:[パスワードを再入力] Password updated successfully! Reloading privilege tables.. ... Success! // 匿名ユーザー削除 Remove anonymous users? [Y/n] y ... Success! // リモートホストからのrootログイン禁止 Disallow root login remotely? [Y/n] y ... Success! // テスト用データベース削除 Remove test database and access to it? [Y/n] y - Dropping test database... ... Success! - Removing privileges on test database... ... Success! // ユーザー権限が保存されているテーブルをリロード Reload privilege tables now? [Y/n] y ... Success! All done! If you've completed all of the above steps, your MySQL installation should now be secure.
my.cnfを編集します。
# cp /etc/my.cnf /etc/my.cnf.bak # vi /etc/my.cnf [mysqld] # mysqldセクションの末尾に追加 character-set-server = utf8 # clientセクションごとファイルの末尾に追加 [client] default-character-set = utf8
MySQLを再起動します。
# systemctl restart mysqld.service
これで環境構築完了です!
【Xcode】UILabelの文字サイズを自動調整する
画面サイズに合わせてUILabelが拡大縮小する場合に、文字サイズも自動調整する方法。
何もしないとどうなるか
サンプルとして、5.5inch(ex. iPhone8 Plus)の画面サイズに合わせてレイアウトを作成しました。
青い四角部分がUILabelで、画面サイズに合わせてサイズが変わります。
まず iPhone8 Plusで表示した場合。問題ありません。
次にiPhone4sで表示した場合。文字が省略されてしまいました。
これを調整していきます。
1. Autoshrinkを有効にする
UILabelにはAutoshrinkという、UILabelのサイズに合わせて文字サイズを自動調整してくれるそのものずばりな機能があります。
Storyboardから設定する場合。
「Autoshrink」を「Minimum Font Scale」にし、下の欄でScaleを指定します。
Scaleは、自動調整時の文字サイズ最小値を、元々の文字サイズに対する比率で入力します。
コードから設定する場合。
label.adjustsFontSizeToFitWidth = true label.minimumScaleFactor = 0.3
文字サイズが自動調整されました。
ただ、これだとラベルぎりぎりすぎるので、余白をつけたい場合は次に進みます。
2. drawTextで余白(padding)を付ける
UILabelのカスタムクラスを作成し、下記のようにdrawTextを実装します。
class AutoShrinkLabel: UILabel { var padding: UIEdgeInsets = UIEdgeInsetsMake(4, 4, 4, 4) override func drawText(in rect: CGRect) { let newRect = UIEdgeInsetsInsetRect(rect, padding) super.drawText(in: newRect) } }
Storyboardからラベルに設定します。
余白がつきました。
大体これでいけるのですが、この方法は縦方向に余白を大きく取りたい場合に上手くいかないことがあります。
おそらく「label.adjustsFontSizeToFitWidth」というプロパティ名の通り、幅に合わせて自動調整しているため。
3. viewDidLayoutSubviewsで余白(padding)を付ける
drawTextでは調整しきれない場合は、UIViewControllerでviewDidLayoutSubviewsを実装して自力で計算します。
こうなるとdrawTextはなくてもいいかも。
class AutoShrinkLabel: UILabel { var padding: UIEdgeInsets = UIEdgeInsetsMake(20, 4, 20, 4) } class ViewController: UIViewController { @IBOutlet weak var label: AutoShrinkLabel! override func viewDidLayoutSubviews() { let fontSize = label.frame.size.height - (label.padding.top + label.padding.bottom) label.font = label.font.withSize(fontSize) } }
以上です!
【Xcode】iOS11からUITableViewのSwipe Actionが新しくなった
iOS11からUITableViewDelegateにSwipe Actionの新しいメソッドが追加されました。
これによって以下のことができるようになりました。
(iOS11以降限定です)
- 左から右へのSwipe Actionを実装する
- Swipe Actionに画像を表示する
使用イメージ
左から右へのSwipe Action使用例です。
こんな感じで文字の代わりにアイコンを表示できるようになりました!
こちらは従来通り右から左へのSwipe Action、文字を表示した場合です。
こちらもアイコンに変えることができます。
サンプルコード
上記の使用イメージで使用したソースコードです。
storyboardで適当なUITableViewControllerと紐づけてください。
class ViewController: UITableViewController { let dataSource = ["One", "Two", "Three"]; override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return dataSource.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = UITableViewCell(style: .default, reuseIdentifier: "Cell") cell.textLabel?.text = dataSource[indexPath.row] return cell } // iOS11以降 // 右から左へスワイプ @available(iOS 11.0, *) override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { let editAction = UIContextualAction(style: .normal, title: "Edit", handler: {(action: UIContextualAction, view: UIView, completion: (Bool) -> Void) in print("Edit") // 処理を実行完了した場合はtrue completion(true) }) editAction.backgroundColor = UIColor(red: 101/255.0, green: 198/255.0, blue: 187/255.0, alpha: 1) let deleteAction = UIContextualAction(style: .destructive, title: "Delete", handler: { (action: UIContextualAction, view: UIView, completion: (Bool) -> Void) in print("Delete") // 処理を実行できなかった場合はfalse completion(false) }) deleteAction.backgroundColor = UIColor(red: 214/255.0, green: 69/255.0, blue: 65/255.0, alpha: 1) return UISwipeActionsConfiguration(actions: [editAction, deleteAction]) } // iOS11以降 // 左から右へスワイプ @available(iOS 11.0, *) override func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { let favoriteAction = UIContextualAction(style: .normal, title: "Favorite", handler: { (action: UIContextualAction, view: UIView, completion: (Bool) -> Void) in print("Favorite") // 処理を実行完了した場合はtrue completion(true) }) favoriteAction.backgroundColor = UIColor(red: 210/255.0, green: 82/255.0, blue: 127/255.0, alpha: 1) favoriteAction.image = UIImage(named: "ic_favorite") return UISwipeActionsConfiguration(actions: [favoriteAction]) } }