結果だけでなく過程も見てください

日々の奮闘を綴る日記です。

CentOS(バージョン7以降)の新規インストール時に行う作業をスクリプト化したもの

新しいバージョンのCentOS/RedHat(バージョン7以降)がリリースされた場合などに使用するスクリプトです。
基本的にセキュリティはゆるゆるなので状況に応じて設定を変更してください。

やっていることはざっと以下の通りです。

  • rootで実行しているかチェック
  • umaskを0022に設定
  • 変更を行うファイルのバックアップをコピーするためのディレクトリ作成
  • SELinux無効化
  • perlのインストール
  • gccのインストール (コメントアウトしてます)
  • gdbのインストール (コメントアウトしてます)
  • Sambaサーバーのインストール (IPフィルタは127.と192.168.1.になってます)
  • firewalldの無効化
  • wgetのインストール
  • SSHでrootログイン不可化 (コメントアウトしてます)
  • umaskを元に戻す
#!/bin/sh


BK_DIR=~/init_backup


function file_backup() {
  srcfile=$1
  dstfile=$2

  i=0
  while [ $i -le 100000 ]
  do
    if [ ! -e ${dstfile}.${i} ]
    then
      cp -p ${srcfile} ${dstfile}.${i}

      if [ $? -eq 0 ]
      then
        echo "[Info ] Copying file succeeded(${dstfile}.${i})."
        break
      else
        echo "[Error] Copying file failed(${dstfile}.${i})."
      fi
    fi
    i=`expr $i + 1`
  done
}


# --------------------------------------------------------------------
# Check Superuser

if [ ${EUID:-${UID}} != 0 ]
then
  echo "[Error] You must run this script with Superuser."
  exit -1
fi


# --------------------------------------------------------------------
# Set umask

OLD_MASK=`umask`
umask 0022


# --------------------------------------------------------------------
# Create backup

echo "################## Create backup directory ##################"

if [ ! -e ${BK_DIR} ]
then
  mkdir -p ${BK_DIR}
  chmod 0755 ${BK_DIR}

  echo "[Info ] backup dir(${BK_DIR}) has created."
else
  echo "[Info ] backup dir(${BK_DIR}) has been already created. Skipped."
fi

echo ""


# --------------------------------------------------------------------
# Disable SELinux

echo "################## Disable SELinux ##################"

cat /etc/selinux/config | grep "SELINUX=disabled" > /dev/null
if [ $? -ne 0 ]
then
  mkdir -p ${BK_DIR}/etc/selinux
  file_backup /etc/selinux/config ${BK_DIR}/etc/selinux/config

  sed -i -e "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config

  # Disable current shell SELinux either.
  setenforce 0

  echo "[Info ] Disable SELinux has done."
else
  echo "[Info ] Disable SELinux has already done. Skipped."
fi

echo ""


# --------------------------------------------------------------------
# Install perl

echo "################## Install perl ##################"

rpm -q perl
if [ $? -ne 0 ]
then
  # perl is not installed.
  yum -y install perl

  sleep 1
fi


# --------------------------------------------------------------------
# Install gcc

#echo "################## Install gcc ##################"
#
#rpm -q gcc
#if [ $? -ne 0 ]
#then
#  # gcc is not installed.
#  yum -y install gcc
#
#  sleep 1
#fi


# --------------------------------------------------------------------
# Install gdb

#echo "################## Install gdb ##################"
#
#rpm -q gdb
#if [ $? -ne 0 ]
#then
#  # gdb is not installed.
#  yum -y install gdb
#
#  sleep 1
#fi


# --------------------------------------------------------------------
# Install & Setup Samba Server

echo "################## Install & Setup Samba Server ##################"

systemctl status smb | grep "Loaded: not-found"
if [ $? -ne 0 ]
then
  # smbd is not installed.
  yum -y install samba

  sleep 1

  # Backup original smb.conf
  mkdir -p ${BK_DIR}/etc/samba
  file_backup /etc/samba/smb.conf ${BK_DIR}/etc/samba/smb.conf

  # Create empty smb.conf, 
  echo "[global]" > /etc/samba/smb.conf
  echo "encrypt passwords = yes" >> /etc/samba/smb.conf
  echo "" >> /etc/samba/smb.conf
  echo "dos charset = CP932" >> /etc/samba/smb.conf
  echo "unix charset = UTF-8" >> /etc/samba/smb.conf
  # echo "display charset = UTF-8" >> /etc/samba/smb.conf
  echo "" >> /etc/samba/smb.conf
  echo "workgroup = WORKGROUP" >> /etc/samba/smb.conf
  echo "hosts allow = 127. 192.168.1." >> /etc/samba/smb.conf
  echo "server string = Samba Server Version %v" >> /etc/samba/smb.conf
  echo "" >> /etc/samba/smb.conf
  echo "security = user" >> /etc/samba/smb.conf
  echo "passdb backend = tdbsam" >> /etc/samba/smb.conf
  echo "" >> /etc/samba/smb.conf
  echo "log file = /var/log/samba/log.%m" >> /etc/samba/smb.conf
  echo "max log size = 50" >> /etc/samba/smb.conf
  echo "" >> /etc/samba/smb.conf
  echo "[shareall]" >> /etc/samba/smb.conf
  echo "path = /" >> /etc/samba/smb.conf
  echo "writable = yes" >> /etc/samba/smb.conf
  echo "printable = no" >> /etc/samba/smb.conf
  echo "public = yes" >> /etc/samba/smb.conf
  echo "create mode = 755" >> /etc/samba/smb.conf
  echo "directory mode = 755" >> /etc/samba/smb.conf
  echo "socket options = TCP_NODELAY SO_RCVBUF=16384 SO_SNDBUF=16384" >> /etc/samba/smb.conf
  echo "" >> /etc/samba/smb.conf

  echo "[Info ] Create Samba user."
  pdbedit -a -u root

  # Start samba service.
  systemctl start smb
  systemctl start nmb

  # Enable to boot samba service automatically.
  systemctl enable smb
  systemctl enable nmb

  firewall-cmd --add-service=samba
  firewall-cmd --add-service=samba --permanent

  echo "[Info] Install & Setup Samba Server has done."
else
  echo "[Info] Install & Setup Samba Server has already done. Skipped."
fi

echo ""


# --------------------------------------------------------------------
# Disable firewalld

echo "################## Disable firewalld ##################"

systemctl is-enabled firewalld | grep enabled
if [ $? -eq 0 ]
then
  # firewalld is now running.
  systemctl stop firewalld
  systemctl disable firewalld

  echo "[Info] Disable firewalld has done."
else
  echo "[Info] Disable firewalld has already done. Skipped."
fi

echo ""


# --------------------------------------------------------------------
# Install wget

echo "################## Install wget ##################"

yum list installed | grep wget
if [ $? -eq 1 ]
then
  yum -y install wget

  sleep 1
fi

echo ""


# --------------------------------------------------------------------
# Disable SSH root Login

#echo "################## Disable SSH root Login ##################"

#cat /etc/ssh/sshd_config | grep -x "PermitRootLogin no"
#if [ $? -ne 0 ]
#then
#  mkdir -p ${BK_DIR}/etc/ssh
#  file_backup /etc/ssh/sshd_config ${BK_DIR}/etc/ssh/sshd_config
#
#  cat /etc/ssh/sshd_config | grep -x "#PermitRootLogin .*"
#  if [ $? -eq 0 ]
#  then
#    sed -i -e "s/#PermitRootLogin .*/PermitRootLogin no/g" /etc/ssh/sshd_config
#  fi
#
#  echo "[Info ] Disable SSH root Login has done. SSH service will be restarted..."
#
#  systemctl restart sshd
#else
#  echo "[Info ] Disable SSH root Login has already done. Skipped."
#fi

echo ""


# --------------------------------------------------------------------
# Set umask back

umask ${OLD_MASK}


echo ""
echo "[Info] All processes has done."

iPhoneアプリにGoogle AdSense, AdMob, Firebaseを使って広告を出す方法まとめ

色々試行錯誤してなんとか広告を表示できたのですが、思ったこと。

なんかWebサービスいっぱいあるし、
なんちゃらIDみたいのいっぱい出てくるし、混乱するよおお!!!

ということで、とりあえず関連図を一枚の画像にしてみました(コーディングまですべて書いてあるよ!)
まずは見易さ度外視でとりあえず全登場人物とその関係を書いてみました。
これさえ見れば、あなたも必ず広告が出せるようになるはず!

かなりデカイ画像なので、ダウンロードして拡大してみてくださいね!
ちなみにIDは適当なので、ご自分のものに置き換えてください。


コーディング

コピペできるように書いておきます。

Podfileはこちら。プロジェクト名はご自分のものに置き換えてください。

# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'MySkillTrain1' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!

  # Pods for MySkillTrain1
  pod 'Firebase/Core'
  pod 'Firebase/AdMob'
  pod 'Google-Mobile-Ads-SDK'
end

AppDelegate.swiftに書くコードはこちら。IDは適当です。ご自分のものに置き換えてください。

import UIKit
import Firebase

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.

        // Use Firebase library to configure APIs
        FIRApp.configure()

        // Initialize Google Mobile Ads SDK, application IDを設定
        GADMobileAds.configure(withApplicationID: "ca-app-pub-2356785678063803~2746526570")

        return true
    }

広告を置くView Controllerのコードはこちら。IDは適当です。ご自分のものに置き換えてください。

import GoogleMobileAds

class ViewController: UIViewController {
    @IBOutlet weak var bannerView: GADBannerView!

    override func viewDidLoad() {
        print("Google Mobile Ads SDK version: \(GADRequest.sdkVersion())")
        bannerView.adUnitID = "ca-app-pub-1245659001912343/1337795797"
        bannerView.rootViewController = self
        bannerView.load(GADRequest())
    }
}

各要素の解説

やる気があれば書きます。
とりあえず各Webサービスへのリンクを書いときます。
IDを取得する順番とか、必要ですかねー?

Google AdSense

AdMob

Firebase console

その他の設定

テストでうっかり忘れがちなのが、ATS(App Transport Security)です。
これで外部との通信を許可しておかないと、広告が表示されません。

Zenphotoを超簡単にインストールする方法 (Linux(CentOS))

はじめに

世の中にはGoogleフォト等の便利な写真用ストレージサービスがありますが、
以下の理由から自宅サーバーにzenphotoを導入することにしました。

  • 長年使用していると何かしら情報が洩れそうで心配
  • 家族全員の携帯で取りだめてる写真や動画や時には写真以外のファイルを容量無制限でまとめてぶっこみたい

今回は自作のスクリプトを使って一発でインストールしています。
スムーズに行けば5分程度で完了し、すぐ使えるようになります。

環境:CentOS 7 (64-bit)

インストール手順

(1)必要なパッケージのインストールと設定

以下の自分が自作したスクリプトをrootで実行します。
setup_zenphoto.sh 直

WebサーバーやDBサーバーの設定を色々と変更するので、怖かったらスクリプトの中身をコピペして手動で実行してってください。本スクリプトを使用して不利益が生じても責任は負いませんのでご注意を…。あと、スクリプトのエラー処理や複数回実行等の処理は適当です。

スクリプトをダウンロードして、中身をテキストエディタで開き、
最初の方にある以下のパラメーターを好きな値に変更してからスクリプトを実行してください。

パラメーター 意味
PHOTO_DBNAME 写真用のデータベース名
PHOTO_DBUSERNAME 写真用のデータベース用ユーザー名
PHOTO_DIRNAME Webサーバーにzenphotoを展開する際のディレクトリ名(そのままURLになります)
SSL_CRT_BASENAME SSL用証明書と秘密鍵のファイル名

実行するコマンドはこちら。
./setup_zenphoto.sh

コマンド中は対話でいくつか入力を求められます。

Enter current password for root (enter for none):

インストール直後はパスワードがないので、そのままEnterキーを押してください。
mariadbをこのスクリプト内でインストールした場合に実行する
 mysql_secure_installationで入力を求められるものです。

Set root password? [Y/n]

「Y」を入力して、パスワードを設定してください。
ここで入力するパスワードは、このスクリプトの第二引数に指定したものと同じものにしてください。

Remove anonymous users? [Y/n]

「Y」を入力してDBのanonymousユーザーは削除しておきましょう。

Disallow root login remotely? [Y/n]

「Y」を入力してDBのリモートアクセスを無効にしましょう。

Remove test database and access to it? [Y/n]

「Y」を入力してtestDBを削除しておきましょう。

Reload privilege tables now? [Y/n]

「Y」を入力して情報をリロードしておきましょう。

Enter pass phrase for <変数SSL_CRT_BASENAMEの値>.key:

SSL通信のための秘密鍵パスフレーズです。
任意の文字列を入力してください。

Country Name (2 letter code) [XX]:
State or Province Name (full name) []:
Locality Name (eg, city) [Default City]:

Country Nameには「JP」、Stateには「Tokyo」や「Kanagawa」など都道府県を、
Locality Nameには「Yokohama」など市や区を入力してください。

Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:

何も入力せずEnterしてください。

Common Name (eg, your name or your server's hostname) []:

実際にhttpsでサーバーにアクセスするアドレスを記載します。
IPアドレスでアクセスするなら、IPアドレスを、
ドメイン名でアクセスするならドメイン名を入力します。

Email Address []:
A challenge password []:
An optional company name []:

何も入力せずEnterしてください。

Please provide the prefix of Imagemagick installation [autodetect] :

何も入力せずEnterしてください。

スクリプトが最後まで実行されると以下が表示されるはずです。
ブラウザでアクセスしてください。(e.g. http://192.168.1.2/myphoto/)

Please contact http://<yoursever>/<変数PHOTO_DIRNAMEの値>/ and setup.
(2)ブラウザで初期設定する

(1)で最後に表示されたURLにアクセスしましょう(の部分は適宜置き換えてください)

まずは以下の画像を参考にして、DBの情報を入力した後、[保存]ボタンを押してください。

データベースエンジン MySQL
データベースユーザ スクリプトの変数PHOTO_DBUSERNAMEで指定したもの
データベースパスワード スクリプトの第二引数に指定したもの
データベース名 スクリプトの変数PHOTO_DBNAMEで指定したもの

次に以下の警告が出ている場合は、「適用」を押下して文字コードUTF-8に変更します。

上の適用ボタンを押すと以下が表示されることがあります。
その場合は「実行してください」の部分のリンクをクリックしてください。

URLオプションUTF8画像URIを有効にすべきです。 実行してください

また、以下の警告が出ることもあるのですがおそらく無視しても大丈夫だと思いますので、
ここまできたら画面下部の[実行]ボタンを押下して、zenphotoのセットアップを開始してください。

警告!

Zenphotoは所有者のみがアクセスできる(パーミッションは0600)zp-dataフォルダーの機密ファイルを作成することをおすすめします。setup.logのファイルのパーミッションは未承認アクセスを許可できる0644である必要があります。
警告!

恐らくアップロードで問題があります。以下のファイルをチェックしてください:
zp-core/zp-extensions/tinymce4/themes/inlite/src/test/.eslintrc

zenphotoのセットアップが完了した後は、[管理ユーザ名とパスワードを設定する]のリンクをクリックして
zenphotoの管理ユーザーと一般ユーザーを作成してください。

管理ユーザ名とパスワードを設定する必要があります。

次に管理ユーザーでログインして、いま上で色々いじっていた
セットアップ画面が外部から見られないように設定を変えましょう。

ログイン後に「Overview」タグをクリック、「Utility functions」グループの中から
「Setup > protect script」をクリックしましょう。

これで完了です!
アルバムを作ったり、写真をアップロードしてみたり色々と試してください。

おまけ

PHPの設定で、デフォルトでは一度にアップロードできるファイル容量が2MBになっているかもしれません。
またファイルを直接配置(デフォルトでは/var/www/html/myphoto/albums/<作成したアルバム名)>してもOKです。

インストールされるパッケージ一覧

スクリプトを実行すると、以下のパッケージがインストールされます。

  • gcc
  • unzip (zenphotoのzip展開用)
  • mariadb, mariadb-server (DBサーバー)
  • httpd (Webサーバー)
  • mod_ssl (httpdSSL通信モジュール)
  • php周りの色々なパッケージ (zenphoto用)
  • imagick (zenphoto用)
  • ImageMagick (zenphoto用)
  • zenphoto
  • zenphotoのiOS用アドイン(オプション)

設定一覧

上記パッケージの設定ファイルなどを自動で編集します。

  • /etc/php.iniにextension=imagick.soを追加
  • スクリプト内の変数PHOTO_DBNAMEのデータベースが作成
  • スクリプト内の変数PHOTO_DBUSERNAMEのデータベース用ユーザー作成
  • mariadbのセキュリティ確保用スクリプトmysql_secure_installationを実行
  • /etc/httpd/confに変数SSL_CRT_BASENAMEのファイル名の秘密鍵・証明書を作成。
  • /etc/httpd/conf.d/ssl.confの証明書・秘密鍵のファイル名を↑のパスに変更
  • zenphotoを/var/www/htmlに展開。所有者・所有グループをapache:apacheに変更
  • /tmp/zenphoto-iOS-plugin-master.zipが存在すればzenphoto
  • httpdのセキュア設定(ServerTokensをProdに変更、TraceEnableをOffに設定等)

スクリプトの解説

やる気があったら書きます。
(でも読めばわかる内容だと思います。読んでみてください。)

Windowsメインだった自分がMacを使用して詰まったところをまとめる

例によって適宜追加の記事です。

スクリーンショットの撮り方がわからない

  • command + Shift + 3で、デフォルトでデスクトップ(?)にファイルが作成されます。
  • command + Shift + 4で、対象を画面全体にしたりウィンドウにしたり選択範囲にしたり細かく指定をしてスクリーンショットを撮ることができます。

Macでデスクトップにファイルが保存したいが、一覧に出てこない

アプリケーションによっては、以下のように選択できる保存先一覧にデスクトップが出てこないのです。

そんなときは

command + D

を押すと保存先がデスクトップに変わります。
これは保存するときだけでなく、ファイルを開くときにも使えます。

#というか、好きなパスを入力させてほしいですね。。。
#(たぶん好きに入力する方法があるとは思うのですが、やり方がわかりません。。。)

Finder上でファイルやディレクトリの絶対パスを取得する

項目を選んでからcommand + iキーで情報ウィンドウを出した後、「場所」の情報をコピーすることで取得できます(以下SS参照)。
「場所」はUNIX形式のパスにはなっていませんが、ペーストするとちゃんとUNIX形式のパスが表示されます。
(以下の例だとペーストすると「/Application」が表示される)

ショートカットキーの記号(特殊キー)の意味がわからない

このサイトに詳しく書いてありました。
http://labs.torques.jp/2011/01/21/1610/

WindowsのMSペイントに代わるアプリケーション

自分はよく画像のサイズ変更を行ったり、説明用にテキストを書き込むことが多いのですが、
そのためにわざわざ多機能のGIMPなどは使いたくないです。もっとシンプルなのが欲しいです。

SkitchまたはPaintbrushが良さそうです。

■Skitch
https://itunes.apple.com/jp/app/skitch-撮る-描き込む-共有する/id425955336?mt=12

■Paintbrush
https://paintbrush.sourceforge.io/downloads/

両方入れて見ましたが、Skitchの方がサイズ変更の方法がちょっとわかりづらかったです。
以下のサイトを参考にとても簡単に実現できました。
http://y-shinozw.hateblo.jp/entry/2013/07/09/151512

両方入れてみて好きな方を選べばいいと思います。

Windowsマシンへリモートデスクトップで接続したい

普通に公式アプリがありました。

Microsoft Remote Desktop
https://itunes.apple.com/jp/app/microsoft-remote-desktop/id715768417?mt=12&ign-mpt=uo%3D4

Mac OSのバージョンを確認する

メニューバーの端に表示されているアップルアイコン→このMacについてを選択する。

BOOTCAMPでMacOSからWindowsに切り替える

  • PCの電源を落とす
  • コンピュータの電源ボタンを押し、すぐに「option」キーを押しっぱなしにする
  • デュアルブートのディスク選択画面が出てくるので、Windowsがインストールされたディスクを選ぶ

参考サイト

ファイルの保存先をデスクトップに指定するMacのショートカットキー - ITEA4.0
http://itea40.jp/technic/shortcut/how-to-specify-the-desktop-to-save-file/

Skitchで画像サイズを変更する方法 - リバネス研究日誌(らぼのーと)
http://y-shinozw.hateblo.jp/entry/2013/07/09/151512

TORQUES LABS
http://labs.torques.jp/2011/01/21/1610/

スクウェア・エニックスのソフトウェアトークン切替方法

携帯を変えたときなど。手順をまとめておきます。

用意するもの

(メールが送られてくるので、受信できるようにしておきましょう!)

1.アカウント管理システムにログインする

任意の端末(PC、任意の携帯)でOKです。
http://sqex.to/YUH

2.強制解除パスワードをメモしておく

ログインしたページの[トークンご利用状況]のところの
[※強制解除パスワード]をコピー、スクリーンショット、カメラ、紙のメモに書くなどしておく。

【注意】このパスワードは登録する度に変化するので、必ずこのタイミングで確認してください

3.ソフトウェアトークンの強制解除を行う

https://secure.square-enix.com/account/app/svc/coercioncan
にアクセスして、ID、パスワード、2.の強制解除パスワードを入れ、[メール送信]ボタンを押す。

4.メールに記載されているURLにアクセスする

スクウェア・エニックスIDに紐づけされているメールアドレスに
メールが届くので、そこに記載されているURLに飛ぶ。
→これで強制解除は完了です!

5.新しい端末でソフトウェアトークンを登録する

再びアカウント管理システムにログインします。
http://sqex.to/YUH

上メニュー[サービス・オプション]→[ワンタイムパスワード]を選択。

続いてご自身の新しいトークンに合わせて、
[セキュリティトークン(キーホルダータイプ)の設定を行うもしくは
[ソフトウェアトークン(スマートフォン用アプリ)の設定を行う]を選択する。

※今回は例として、スマホを選択します。キーホルダータイプの人は以降は自力で頑張ってください(丸投げ)。

[ソフトウェアトークンの登録]を押下する。
[次へ]を押下する。
[利用規約に同意してメールを送信]を押下する。

6.ソフトウェアトークンに情報を入力

新しい端末のソフトウェアトークンを起動して、以下を入力する。

これにて完了です!おつかれさまでした。

おまけ 「強制解除パスワード」を保管しておらず、自身で解除が行えない場合

ここを参照してください。
http://support.jp.square-enix.com/faqarticle.php?kid=74267&id=450&la=0
http://sqex.to/gYp

C# WPFアプリケーションの終了方法あれこれ

終了方法が色々あったのでまとめてみました。
他にも考慮すべき点があった場合は,加筆します。

  Shutdown関数 Application.Current.Shutdown関数 Environment.Exit関数 Close関数
Appクラス Shutdown→後続コード→App.OnExit()→App.Run()直後 Shutdownと同じ 即アプリケーション終了
MainWindowクラス 長いので以下参照 即アプリケーション終了(Closing関数なども呼ばれず) 長いので以下参照

MainWindowのApplication.Current.Shutdown関数

OnLastWindowCloseの場合

最後のウィンドウを終了した場合だけ,↓の終了モードの動きをする。

OnMainWindowCloseの場合

メインウィンドウを終了した場合だけ,↓の終了モードの動きをする。

OnExplicitShutdownの場合

とにかく↓の終了モードの動きをする。

終了モードの動作

Application.Current.Shutdown();
 ↓
後続のコード〜関数終了
 ↓
App.OnExit()
 ↓
その後,App.Run()の直後へ移動。

終了モードでない場合

Application.Current.Shutdown();
 ↓
後続のコード〜関数終了

MainWindowのClose関数

OnLastWindowCloseとOnMainWindowCloseの場合

Application.Current.Shutdownと同様の動作をする。
Closing関数などはコールされる。

OnExplicitShutdown

Application.Current.Shutdownの「終了モードでない場合」の動作をする。

メインウィンドウについて

一番最初に作成されたMainWindowがメインウィンドウとなる。
App.MainWindowプロパティで取得・変更が可能だ。

シャットダウンモードについて

App.ShutdownModeプロパティで変更できる。

Swift文法まとめ(適宜更新)

最近、ついに人生初のMacを買いました!!
これで思う存分、スタバでドヤれます!!

で、早速iPhoneアプリを作ってみようとぽちぽちやっているのですが、
SwiftやらCocoaやらXcodeやら、いやもう色々と全く新しい環境だとうまく組めなくてもどかしさMAXですね。

とりあえず、備忘録として覚えにくそうな文法をまとめたいと思います。
例によって適宜更新系記事となります。

環境

MacOS 10.12.2 Sierra
Swift 3.0
Xcode 8.2.1

Tuple

基本的な使い方

StringとIntのTupleの定義、初期化、データの追加は以下の通り。

// 型宣言、初期化
var tupleArray:[(name:String, age:Int)] = [(name:"Joel", age:48), (name:"Airi", age:2)]

// 追加
tupleArray.append((name:"Ellie", age:14))
Tupleの配列で、Tuple中の一部の値がマッチするか検索して、見つかったインデックスを取得する

上の例でいうと、年齢は関係なく名前が"Airi"の人を探して、その配列のインデックスを取得したい!と言った場合のサンプルは以下になります。

if let index = tupleArray.index(where: {$0.name == "Airi"})
{
    print("name:\(tupleArray[index].name)  age:\(tupleArray[index].age)")
}

Swift 3.0以降のfor文

Swift 3.0からは使い慣れたfor文が使えず、代わりに以下の構文を使う必要があるようです。

for index in 0..<array.count
{
    print(array[index])
}

逆順(降順)にカウントしたい場合はこれ!

for index in (0..<array.count).reversed()
{
    print(array[index])
}

C#とかのforeach的な構文はこちら。

for data in array
{
    print(data)
}

配列

変数を定義し,空の配列で初期化する場合。

var intArray : [Int] = []

ディクショナリ

ディクショナリを定義し,空で初期化する場合。

// 人の名前(String)がキー,年齢(Int)がデータのディクショナリ
var personAgeMap: [String:Int] = [:]
値の追加と変更
var personAgeMap: [String:Int] = [:]

// 追加(キーが存在しなければ追加になる)
personAgeMap["Joel"] = 48

// 変更(キーが存在すれば変更になる)
personAgeMap["Joel"] = 14
キーに対応するデータがあるか存在確認したい
var personAgeMap: [String:Int] = [:]

 :

if let age = personAgeMap["Airi"]
{
     // "Airi"という人物の情報が存在する!
}
自作クラスをキーにする場合

例えば以下のようなゲームに出てくるスキルに関するクラスがあって,スキル名,属性,スキルポイントなどのデータを持っている場合。

class SkillInfo
{
    // スキル名
    var strSkillName : String

    // スキルの属性
    var nAttribute : Int

    // スキルポイント
    var nSkillPoint : Int
}

このうちスキル名をキーにしたいと思った場合。以下のコードを追加する。

extension SkillInfo : Hashable
{
    var hashValue : Int
    {
        return self.strSkillName.hashValue
    }
}

// SkillInfo同士を比較する際の==のオーバーロード
func == ( lhs : SkillInfo, rhs : SkillInfo ) -> Bool
{
    return lhs.strSkillName == rhs.strSkillName
}

これで以下のようにディクショナリのキーとして使うことができます。

var skillJobMap : [SkillInfo : JobInfo] = [:]

UserDefaults

こいつにデータを格納しておくと,データを永続化できます。

基本的な使い方

以下のように取得したsettingsに対してデータの取得や設定を行います。

let settings : UserDefaults = UserDefaults.standard
値の設定(Int型の値を設定する場合)

forKeyは「K」が大文字なので注意です。これでしばらく悩んだことがあります。。。
(小文字にすると,Argument labels '(_:, forkey:)' do not match any available overloadsと言われてしまいます)

let point : Int = 40

settings.set(point, forKey:"Joel")
値の取得(Int型の値を取得する場合)
let point : Int = settings.integer(forKey: "Joel")

配列のfilter

配列の中から条件にあったものだけを取り出したいときはfilterを使います。
以下はJobInfoというクラス配列の中から、JobInfoクラスがもつスコアが60より大きいものを選び出して、filteredJobsという変数に格納する例。

// JobInfoクラスの配列
let targetJobs : [JobInfo] = ....

let filteredJobs = targetJobs.filter({
                    (item) -> Bool in return item.score > 60
                })
プライバシーポリシー お問い合わせ