アプリなどを開発するブログ

React Native / Swift / Ruby on Railsなどの学習メモ。


gitでリモートのブランチをローカルに持ってくる

git でリモートの他の人のブランチを持ってきて作業したい時ってありますよね。
今まで自分はこれやりたい時、ネットで検索して出てきた以下のコマンドでやってました。

$ git fetch
$ git checkout -b branch_name origin/branch_name

しかし、こんな長ったらしいコマンドではなく、以下でよいということに気づきました。
お恥ずかしい限り。

$ git fetch
$ git checkout branch_name

【iOS】フェードで切り替わるContainer ViewController メモ

iOS (or macOS) でアプリを作る際、ログイン中なら普通の画面、未ログインの場合はログイン画面を表示、という処理は頻発すると思います。

モーダルでログイン画面を出すという方法もありますが、色々面倒なのでApple公式で「Container View Controller」と呼ばれている手法で VC1 in VC2 という構造にして、VC1はずっと生きていて、その中の子であるVC2を切り替える、とするのが一般的だと思います。

iOS View Controllerプログラミングガイド: Container View Controller を実装する

Storyboardでは「ContainerView」というパーツがObject Libraryに用意されていますが (実体はUIViewのようです)
f:id:device_me:20180611113840p:plain

コードで実現する場合は気にすることがちょいちょいあって、忘れがちなので自分用のメモです。
switchToメソッドでViewControllerを切り替えます。
遷移時のエフェクトはシンプルなクロスフェードです。

class MainViewController: UIViewController {
    private var currentVC: UIViewController!

    func switchTo(_ newVC: UIViewController) {
        guard let oldVC = currentVC else {
            show(newVC)
            return
        }

        newVC.view.alpha = 0.0
        addChildViewController(newVC)
        oldVC.willMove(toParentViewController: nil)

        transition(from: oldVC, to: newVC, duration: 0.5, options: UIViewAnimationOptions.transitionCrossDissolve, animations: {
            oldVC.view.alpha = 0.0
            newVC.view.alpha = 1.0
        }, completion: { [weak self] _ in
            self?.currentVC = newVC
        })
    }

    private func show(_ vc: UIViewController) {
        currentVC = vc
        addChildViewController(vc)
        view.addSubview(vc.view)
        vc.didMove(toParentViewController: self)
    }
}

参考

www.slideshare.net

App Kitで自動フルスクリーン

NSWindowのtoggleFullScreenメソッドを使う。

import Cocoa

class ViewController: NSViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func viewDidAppear() {
        super.viewDidAppear()

        view.window?.collectionBehavior = NSWindow.CollectionBehavior.fullScreenPrimary
        view.window?.toggleFullScreen(nil)
    }

    override var representedObject: Any? {
        didSet {
        // Update the view, if already loaded.
        }
    }
}

App Kit でバッテリーの状態を取得

WWDC 2018でiOS アプリをMacに移行できるようにする方針が発表されました。
Apple は AppKitをUIKitっぽく作り直して発表するはず、という噂はかなり前から囁かれていましたが、
UIKitがMacOSでも動くようにしてる、という理解が正しそうです。
f:id:device_me:20180605120844p:plain おそらく、UIKitだけでMacアプリが作れるというよりは、AppKitも使用しながら、UIKitで書かれた部分もまるっと持ってこれるようになる感じ?

jp.techcrunch.com

ですのでMacアプリを作りたいならどのみちApp Kitの勉強も必要。

自分はバッテリー状況や加速度センサーの値に応じていろいろ起こるアプリを作りたいと思ってます。
バッテリーはIOKitを使えばできそう。
IOPowerSources.h | Apple Developer Documentation

しかし、加速度センサーの値はmacOSアプリだと取得できなさそう?
ぬーん。

reduxのreselectについて調べた

reselectは主にreduxで利用される、計算結果のメモ化を担うライブラリ。
とはいえreduxに依存しているわけではないので、単体でも使える。

github.com

使い方はざっくりこんな感じ。
createSelector 関数で、メモ化selectorをつくる。

input-selectors の値が変わるような Redux ステートツリーの 変更があると、transform function が呼ばれる。 (transform functionの引数はinput-selectorの実行結果)

input-selectorsの値が前回呼ばれた時と一緒なら、 transoform function を実行せずに、前回計算された値を返す。

f:id:device_me:20180601112959p:plain

iOS マルチディスプレイ Swift 4

iOSでマルチディスプレイする際のコードをswiftで書き直してみたメモ。

 // 複数 window 対応

    private func checkForExistingScreenAndInitializeIfPresent() {
        if UIScreen.screens.count > 1 {
            // 外付けディスプレイを表す画面オブジェクトを取得する。
            let secondScreen = UIScreen.screens[1]
            print("secondScreen.preferredMode : ", secondScreen.preferredMode)

            // 画面の大きさを取得して、正しい大きさのウインドウを生成できるようにする。
            let screenBounds = secondScreen.bounds
            let screenBounds = CGRect(x: 0, y: 0, width: 2400, height: 1500)

            secondWindow = UIWindow(frame: screenBounds)
            secondWindow?.screen = secondScreen

            // 当初の表示内容を設定する
            if let vc = R.storyboard.settings().instantiateInitialViewController() {
                secondWindow?.rootViewController = vc
            }

            secondWindow?.isHidden = false
        }
    }

    private func setUpScreenConnectionNotificationHandlers() {
        NotificationCenter.default.addObserver(self, selector: #selector(handleScreenDidConnectNotification(notification:)), name: NSNotification.Name.UIScreenDidDisconnect, object: nil)

        NotificationCenter.default.addObserver(self, selector: #selector(handleScreenDidDisconnectNotification(notification:)), name: NSNotification.Name.UIScreenDidDisconnect, object: nil)
    }

    @objc private func handleScreenDidConnectNotification(notification: Notification) {
        guard let newScreen: UIScreen = notification.object as? UIScreen else {
            print("setUpScreenConnectionNotificationHandlers 失敗")
            return
        }
        let screenBounds = newScreen.bounds
        if secondWindow == nil {
            secondWindow = UIWindow(frame: screenBounds)
            secondWindow?.screen = newScreen
            // ウインドウの初期UIを設定する。
        }
    }

    @objc private func handleScreenDidDisconnectNotification(notification: Notification) {
        if self.secondWindow != nil {
            // ウインドウを非表示にしてから削除する。
            self.secondWindow.hidden = true
            self.secondWindow = nil;
        }
    }

Unable to resolve module 'events' from /node_modules: Module does not exist in Haste module map

FeedMe とか xml2js とかをtypescript + React Native で使おうとしたら出たエラー。

解決方法は以下のライブラリを追加することだそうです。

npm install events buffer stream timers --save

github.com