t__nabe_log

雑多 作業、学習ログ多め。

2019年ブックマーク棚卸しをしたのでブクマして個人的に良かった記事を列挙

実務に関係のあるiOS関連のものは省く。読んでよかった記事を列挙するだけ。なるべく感想書いてるけど不要と思われるもの(読んだほうが話が早いもの)は何も書かない。

棚卸しをしようと思ったきっかけははてなブックマーク棚卸し - naoyaのはてなダイアリー

以下のジャンルは一切取り上げない。

  • 政治に関すること
  • 経済に関するニュース

理由は自作しているフィルタアプリを通してはてブを見てるのでこれらのジャンルに類する記事を見ないため。

Oculus Quest、個人的に今年買ってよかった家電・ガジェットに入ると思うがVRChatはまだ未経験。やってみたくなった

本を読んでるような濃い記事。

毎年数学って何の役に立つのみたいな話とか計算順序の話がSNSでバズってるけど、今年もいつものようにそのネタで盛り上がってる時に話題になった小説だったと思う。ネタとして楽しめた。

20代も数年で終わるのと、自分より若い人たちと触れる機会も多いのでなるべく相手に威圧的な印象を与えないよう意識的にならないといけないと最近よく思う。

Twitterでコンピュータを異民族に例えたツイートをまとめたScrapboxページ。

YoutubeライブストリーミングをしていたChilled cowを認知していたので歴史的経緯を知れて面白かった。

気持ち良い文章だった。

この方の文章が好き。お好み焼き編も面白かった。真似してキムチ鍋一週間分買って毎日キムチ鍋食べたけど4日目ぐらいで食欲わかなくなった。

神経科学について。「神経科学者はマイクロプロセッサを理解できたか」という論文を元に。

そう遠くない将来のこと。その前に自分が死んでる可能性もなくはないが。

ブコメ含めて全部読んだ。油揚げすぐだめになるので助かった。思ったより多くのものが冷凍できることに気づいた。

このため2ch系まとめサイトとしては珍しく住民から絶大な支持を得ており、2ch転載禁止騒動の時にも戦国時代(仮)板では「いい話、悪い話まとめがなくなるから転載全面禁止に反対」との声が挙がり議論は立ち消えとなった。

そんなサイトがあるとは知らなかった。今ではRSSに登録している。

EM菌をきっかけに色々調べていた時にみつけた記事。面白かった。

この件とダウンロード違法化拡大は関わりのある領域だけに記憶に残っている。

自分のある行動の理由を立ち止まって考えるの大事なことだなと改めて思った。

記事内で同じテーマで考えた記事のリンクが掲載されていてそれも含めて良かった。自分の状態を見極めて他人に圧を与えないようにしたい。つまるところ状態が悪い時は休むなりリモートにするなりして人と接触しないようにしたい。しばらくしたら戻るので。

Quora、これ含めて今年はいくつか面白い回答があった。

人から直接薦められたものは買うか実際に触りに行くようにしているが興味の幅が広がって良い。一人だと仕事に関わる領域に触れるかFPSしかしないだろうから。継続したいが継続できるのは今の会社に転職して生活水準が向上したからだとも思う。結局金、貧すれば鈍する、お金の余裕は心の余裕ってことも思い知らされて少し落ち込んだ。

失敗知識データベース、一時期話題になったの思い出した。失敗学の書籍の方は購入したけど積んだままになっている。

仕事柄publicな記事を書くことがある。綺麗な文章が書きたいわけではないが読みやすい文章は書けるようになりたい。

休日になんとなくナチスのヨーゼフ・ゲッベルスについて調べていた時にブクマした記事。

今年記憶に残ってる記事の一つ。

やる夫スレみたいで読み物として面白い。Twitter見に行ってみるとリプで他のアライさんとの掛け合いがなされていてそこも面白かった

この記事をきっかけに新書は読み上げで聴くようになった。技術書も試したことがあるが無。

古のインターネット。功罪あるけど2chは文化を作っていたし今のネタもその焼き回しやもとを辿れば2chっていうことがよくある。

棚卸しでブクマしてるのに気づいて今作っている。

棚卸しで気づいた。今日食べたが美味しかった。

これに近いこと最近よく考えている。

ランキング・列挙系で良かったやつ

これ系、アフィで稼ぐ常套手段なので品質低いの多い印象がある

福岡

ソフトウェア

別業界だけどバズワードの件は思うところがある。

自分の成果物への姿勢について。卑下と謙遜。

今年の転職活動の時参考にした。この業界当たりとハズレの断絶すごい(格差みたいになってるように感じる)ので転職活動はじっくりやった方が良いと思う。

この業界に入って短期的な仕事やお金の心配がほぼなくなりつつあるが最近そのさきのことを気にするようになった。健康、保険、投資とか

ReactのコアメンバーDan Abramov氏の記事。

新規ニュースアプリに間接的に関わってた時に推薦システムについていくらか調べていた。

去年バズった文系でプログラマーになったけど色々失敗して3年半で会社を辞めた話|denkigai|noteを受けての記事。

マネジメントについて。マネジメントには今は興味が薄いけど無知で良いってわけじゃないと思うので一読はした。

ブックマーク棚卸しをした感想

年末に読む、と決めて気軽にブクマできたので来年もやろうと思う。冬休みに腰を落ち着けてじっくり色んな記事を読んでそれをきっかけにいくつか購入したり改めて自分で調べてみたいことも増えたので棚卸ししてよかった。ブックマークするだけして忘れることも一昨年は多かったので良い機会だったが記事を読むのに数日潰れたのがちょっと大変だった。

リモート勤務を快適にするためデスク環境を整えている話

メモはScrapboxに、日頃のアウトプットはDev.IOやGitHub、Qiitaにとなってこのブログで記事を書く機会が減ってしまった。技術的なものでないなにかはTwitterにつぶやいて満足せずにここに書いておきたいと思う。

本題に入る。 現職ではリモートワークが手軽にできるので、自宅で快適に作業できるように環境を整えている。アフィリエイトがしたいわけではないのと、自分が購入したものがベストとは思っていなくて、それぞれの住環境や感覚に合うものを探すべきと思っているのでリンクは貼らない。

今年買ったもの

  • 4kモニタ
  • スチーム加湿器
  • でかい机
  • モニターアーム
  • 自分に合う椅子
  • 山田照明のZ-LIGHT
  • 自作キーボード
  • Oculus Quest
  • iPad

4kモニタ

でかい画面、視野に収められるエリアが増えるのでXcodeみたいな画面幅を取るアプリケーションもブラウザを参照しつつ操作するみたいなことが一画面でできるようになった。MacBook Pro、OS以外必要としていないのでクラムシェルでも全く苦痛がなくなった。4kモニタを横向きにしてもう一つのモニタを縦向きにして作業を行っているが4kモニタも良いけど縦長の画面も非常に便利。主にこちらはブラウザやTwitterなど閲覧が主なアプリケーションのために使っている。

Type-C接続で給電できるタイプを買ったが目障りなケーブルをすっきりできるのが解像度より正直うれしかった。

スチーム加湿器

風邪を引いたのをきっかけに自宅の湿度に気を遣うようになった。スチームタイプにした理由は手入れが簡単なところ。仕組み的にはやかんでお湯を沸かしているようなものなので定期的な専用の薬剤による洗浄を1ヶ月から2ヶ月に一回行う必要はあるが許容範囲内。

でかい机

限られたスペースのやりくりを考えるより扱えないぐらい大きい机にしてしまった方が考えることが少なくなってよかった。欠点は関係ないものが机の上に置かれがちなこと(請求書とか)。縦100cmx横180cmのタイプを買った。

モニターアーム

デュアルモニタ用のモニターアームを買った。前後左右に動かせるタイプ。せっかくの大きなデスクをディスプレイに専有させるのはな、という気持ちで購入。エルゴトロンの購入検討中

自分に合う椅子

Baron(バロン)シリーズ CP45AR-FDH1を使っているが実際に試座して決めた。2万円ぐらいのチェアと最後まで迷った。ソフトウェアエンジニアである限り腰を大切にしないと辛いだろうと思うのでここはお金を惜しまなかった。

山田照明のZ-LIGHT

前職のオフィスで導入されていて欲しいと思っていた。他のデスクライトに比べて大きくて頑丈なので変更のストレスが少ない。無骨なデザインも好み。

自作キーボード

半分趣味になっているので贔屓目もあるが、9個ぐらいキーボードがあるので体調や気分で使うキーボードを変えている。気分転換にも良い。一日のうち殆どの時間キーボードとトラックボールマウスを触っているのでこれからもお金を注ぎ続けると思う。

ケンジントンのSlimBlade Trackball

手首を起こしながら使うと疲れるのでSlimBladeを購入。それでも高いのでリストレストを使っている。指先だけでポインターが動かせるので負担が少ない、これに尽きる。トラックボールは親指タイプなど他に様々な形状のものがあるので一通り触ってみるのがよいと思う。 有線なのがたまに傷。

Oculus Quest

リモートで心配なのが自発的に行わない限り運動が一切必要ないこと。かといってウォーキングやランニングを毎日するのが辛い。ということで買ったのがOculus Quest。Beat Saberのためだけに買った。目論見通り楽しすぎるので体調が悪い日以外は毎日続けている。Beat Saberを遊べる環境としては最安だと思う。難易度を上げると30分から1時間程度で汗だくになる。

iPad

ドキュメントやニュース、電子書籍を退勤打刻後にだらだらしながら読んでいる。これがない時はYoutubeを垂れ流しているだけだったので買ってよかったものに入ると思う。料理を作るときにも便利

これから

  • スマートホーム化を進めているので引き続き。カーテンの開閉を手軽にできるガジェットがクラウドファンディングで資金集めをしていたので投資した。
  • 楽に自宅を清潔に保つ方法を見つける。定期的に掃除しているものの元来いい加減な性格なのでストレスを感じる。ルンバなりお手伝いさんなり自分の負担を減らしたいところ
  • ホットクッカー。 知り合いが購入していた。料理も手軽にできる方法を模索しているので欲しい
  • 食洗機 料理の後の後片付けストレスでしかないので欲しい
  • 引っ越し。リモートを始めて寝室と作業するスペースが同室なのはよくないと思ったので広い家に引っ越す予定

欲しいものややりたいことが山積みだが現状でもかなり快適。悩みは会社に行くと自宅の環境が良すぎて少しストレスを感じること。

MVVM, RxSwiftの学習メモ その1 RxExampleのコードを読む

MVVM及びRxSwiftの学習を始めたので勉強したことをメモしています。 RxExampleのうち、GitHubSignup1はRxSwiftでつかわれるDriverなどを使用していないとのこと。全くRxSwiftのこともMVVMのことも理解していない状態で手探りで進めています。何か誤りがあればお知らせください。

GitHubSignup1での各層の役割

ViewController

ViewModelの役割

  • API用のロジックなどをイニシャライズのタイミングで外部から用意
  • イニシャライズで受け取ったObservableを出力に変換

コードを読む

ViewController初期化時に行われていることの概要

GitHubSignupViewController1はViewDidLoadのタイミングでViewModelを初期化しています。viewDidLoad内でのみ使用されていてGitHubSignupViewController1はプロパティとしてViewModelを保持していないです。 ViewModelの初期化時には引数inputにIBOutletで接続した各UIコンポーネントのプロパティをObservableに変換して渡してます。引数outputには依存するモジュールをまとめて渡しています。引数は両方共tupleです。 その後ViewModelの必要なプロパティにバインドして結果をViewに反映させています。

※今この時点でわからないこと - ViewModel破棄しても大丈夫なの?出力のストリームは破棄されないなのだろうか(ViewModel自体は持つべき情報がもうないからすぐに破棄してるんだろうと思います。)

ViewModelの出力をViewにバインドさせる

この処理を各部分でsubscribeとbind(to:)を使い分ける基準んがわかりませんでした。 bind(to:)を使う方が簡潔に書けるようです。 しかし、bind(to:)を使うには条件があるみたいで、

extension ObservableType {
  public func bindTo<O>(_ observer: O) -> Disposable where O : ObserverType, Self.E == O.E {
  //
  }
}

引数OがObserverTypeにconformしていて、かつObservableTypeにconformしているSelfのEとO.Eで==の関係が成り立つ場合に限るとなっています。 今回bind(to:)でバインドされているのを一つ取り出してみると

viewModel.validatedUsername
            .bind(to: usernameValidationOutlet.rx.validationResult)
            .disposed(by: disposeBag)

レシーバーがObservableで引数には usernameValidationOutlet.rx.validationResultが割り当てられています。usernameValidationOutlet.rx.validationResultはBinderで、Binderはpublic struct Binder: ObserverTypeでObserverTypeにconformしているのでbind(to:)メソッドによるバインドが可能になります。値をそのまま反映させるだけならこれで十分ということでしょうか。

Binderについて

  • エラーのバインドは不可
  • バインディングが特定のスケジューラで確実に実行されるようにしてくれる
  • Binderはターゲットを保持しない ターゲットが解放された場合には要素はバインドされない。

DisposeBagについて

disposeBagオブジェクト自身が破棄されるタイミングで登録されたsubscriptionをまとめて破棄する仕組みです。

Observableを変換

validatedUsername = input.username
            .flatMapLatest { username in
                return validationService.validateUsername(username)
                    .observeOn(MainScheduler.instance)
                    .catchErrorJustReturn(.failed(message: "Error contacting server"))
            }
            // ここでHot Observableに変換してる
            .share(replay: 1)  

上のコードを見ると、input.username: Observableからmapで文字列を取り出してvalidatenServiceの処理を適用してその結果をreturnしてストリームに変換されています。

shareが何をしているのか全く想像できなかったため、調べているとHot ObservableとCold Observableという表現が多く目に付きました。これについて解説しているのがRxSwiftのdocumentationにあります。 RxSwift/HotAndColdObservables.md at master · ReactiveX/RxSwift

Hot Observable

  • ストリームの途中に挟むとsubscribeするより前にストリームを稼働させることが出来る
  • 上流のCold Observableの起動と値の発行要求
  • ストリームを分岐させる
  • 自分から値を発行

Cold Observable

  • 自分から値の発行は不可
  • subscribeしてから動作
  • ストリームの分岐不可

share(replay:)はCold ObservableをHot Observableに変換します。subscribeされるたびに動作してしまうのを避けるためにHot Observableに変換しているようです。

shareメソッドを呼び出さずにsubscribeした際にflatMapLatestが2度呼ばれていることを以下のコードをinitializerに挿入することで確認します。

let hoge = input.username
            .flatMapLatest { username -> Observable<ValidationResult> in
                print("called flatMapLatest")
                return validationService.validateUsername(username)
                    .observeOn(MainScheduler.instance)
                    .catchErrorJustReturn(.failed(message: "Error contacting server"))
        }
        
        _ = hoge.subscribe({ _ in
            print("subscribed count 1")
        })
        _ = hoge.subscribe({ _ in
            print("subscribed count 2")
        })

ログには

called flatMapLatest
subscribed count 1
called flatMapLatest
subscribed count 2

と表示されました。shareメソッドを追記すると

called flatMapLatest
subscribed count 1
subscribed count 2

と表示されました。やはりCold ObservableからHot Observableへの変換が行われているようです。そのメリットがあることもわかりました。

flatMapLatestメソッド

initializer入力シーケンスから出力シーケンスへの変換の際、usernameの入力を出力に変換する部分のみmapではなくflatMapLatestを使用しています。

flatMapメソッドは元のObservableのイベントをObservableに変換して、その発行するイベントをマージするのに対して、flatMapLatestは次のイベントが来た時に前のイベントの処理をキャンセルします。

public func flatMapLatest<O>(_ selector: @escaping (Self.E) throws -> O) -> RxSwift.Observable<O.E> where O : ObservableConvertibleType

まとめ

わからないことをそれぞれ章立てしてメモしていきました。初めてコードを読んだ時は全く何をやっているか把握できなかったのですが、一通り読んだ後は何をしているか理解できるようになりました。メモの途中にあげた疑問点が解決したら記事を新たに作り、リンクを貼るようにします。

Swiftのextension内でのmethodのoverrideについて

@_monoさんのツイートがきっかけでdocumentationやstackoverflowを調べたりplaygroundで遊んだりしたのでそのログ。

extensionでoverride出来る時と出来ない時がある

UIViewControllerのSubclassだとmethodのoverrideが出来る。UIViewControllerのSubclassだと出来るのでは?と思ってObjective-Cのクラスを継承していないSuperclassを用意してそれを継承したSubclassでmethodのoverrideを行ってみたら警告が出た。

Overriding non-@objc declarations from extensions is not supported

SuperClassにNSObjectを継承させてobjc由来のmethodを定義して、SubClassにextension内でoverrideさせると警告はなくなる。

// 警告が出ないコード
class Animal: NSObject {
    @objc dynamic func say() -> String {
        return "Animal"
    }
}

class Cat: Animal {
    
}


extension Cat {
    override func say() -> String {
        return "Cat"
    }
}

objc由来の型に関してはSwiftで書いていても動作はObjective-Cのruntimeのよう。 classとmethodの療法がObjective-Cでないと動かないのはobjc_msgSendでメソッドコールをしている。

ここまでの参考 Swiftにおけるmethod dispatchについて qiita.com

Objective-Cの動的なメソッド呼び出しについて qiita.com

StackoverflowでのOverriding methods in Swift extensionsについての質問

stackoverflow.com

Appleのdocumentationには

Extensions add new functionality to an existing class, structure, enumeration, or protocol type. This includes the ability to extend types for which you do not have access to the original source code (known as retroactive modeling). Extensions are similar to categories in Objective-C. (Unlike Objective-C categories, Swift extensions do not have names.) Extensions can add new functionality to a type, but they cannot override existing functionality.

https://docs.swift.org/swift-book/LanguageGuide/Extensions.html

とあるのでこれらのことを踏まえると今まで通りSwiftでは、基本的にextension内でmethodのoverrideを行わない方針で問題なさそう。 何かご指摘があればにt__nabe(なべ) (@t__nabe) | Twitterにお願いします。

Swift実践入門を再読する

iOS開発を初めた当初に一度Swift実践入門を一気に通読してから業務でアプリ開発に入った。それまで半年ほどRailsでWebアプリケーションの開発をしていきなりのモバイルアプリ開発なのでかなり苦労した。それでも少しずつ開発を勧めてやっとこの前ストアにリリースできた。社内で使ってもらう状態にできて新しいデザインと新機能の追加の要望が来たので、宣伝込みの正式なリリースへ向けたアップデートを現在進めている。その過程でSwiftらしいコードを書いて少しでも楽に機能追加やリファクタリングを行いながらSwiftの言語仕様についてきちんと理解したいと考えて以前読んだSwift実践入門を再読することにした。この記事をそのログとして残そうと思う。基本的に自分がうろ覚えになっていた所を残す。

また、記載されているコードはいずれも本とは異なるコードです。 blog.jnito.com を読んで大いに納得したのが理由だが、ブログを書くときにコードも考えているため書籍に紹介されているコードと比べて意味が理解しづらいものも多いかもしれない。playgroundで動作確認済み。

コードの実行環境

Swift4.2

Xcode Version 10.1

制御構文

caseのwhereによる条件指定

caseのwhere。case文、主にenumに使ってwhere句を使った柔軟な分岐をそもそもしなくて済むようにしたくて使っていなかったが、UILabelのtextプロパティに入れる文字列を投稿時間で分けるDate型のextensionを実装する時に使った。

let score = (70, 60)
switch score {
case (let english, let math) where english == 100 && math == 100:
    print("満点")
case (let english, let math) where english >= 70 && math >= 70:
    print("両方70点以上")
case (let english, _) where english >= 70:
    print("英語は70点以上")
default:
    print("それ以外")
}

for case

もっとはやく使えば良かった。where以降の条件に一致する場合、ループ内の処理を実行する。UIStackView内を実データの配列を使ってaddArrangedSubview(_:)していく時に、forやifを使っていたのを思い出してこれを読んだ後書き直した。

let mediaList: [Media] = [
    .book(title: "ドラえもん 本1", author: "藤子・F・不二雄", year: 1997),
    .book(title: "ドラえもん 本2", author: "藤子・F・不二雄", year: 1999),
    .book(title: "ドラえもん 本3", author: "藤子・F・不二雄", year: 1999),
    .movie(title: "ドラえもん 映画1", director: "藤子・F・不二雄", year: 2004),
    .movie(title: "ドラえもん 映画2", director: "藤子・F・不二雄", year: 2007),
    .website(urlString: "https://ja.wikipedia.org/wiki/%E8%97%A4%E5%AD%90%E3%83%BBF%E3%83%BB%E4%B8%8D%E4%BA%8C%E9%9B%84")
]

print("映画版列挙:")
for case let Media.movie(title, _, year) in mediaList {
    print(" - \(title) (\(year))")
}

// 映画版列挙:
//  - ドラえもん 映画1 (2004)
//  - ドラえもん 映画2 (2007)

repeat-while

通常のwhile文だとwhileの条件によっては一度{}内の処理が実行されないかもしれない。条件式の正否を問わず{}内の処理を必ず行う場合にこれを使う。

var a = 10
repeat {
    print("実行されました")
    a += 1
} while a == 10

クロージャ

クロージャの属性

両方使いどころはわかっていたが使い方をなんとなく知っていただけだった。読むまでautoClosure属性は引数をクロージャで包むという処理を暗黙的に行っているのを知らなかったので、 これをつけたら遅延評価される程度の理解だった。実際に遅延評価をのメソッドを実装してからそれを簡単に書けるautoclosure属性を使った実装に変更するとなるほどとなった。

型の構成要素

サブスクリプト

サブスクリプトを自分で定義できる。サブスクリプトオーバーロードも普段意識せずに当然のように使っていた。サブスクリプトオーバーロードの例としてArray型が挙げられていて(Intを引数に取ってElement型の要素を返すサブスクリプトとRangeを取ってArraySlice型のスライスを返すサブスクリプト)わかりやすかった。

// サブスクリプトの独自実装サンプル
struct StudentNumber {
    var numbers: [[Int]]
    subscript(classNumber: Int, studentNumber: Int) -> Int {
        get {
            return numbers[classNumber][studentNumber]
        }
        set {
            numbers[classNumber][studentNumber] = newValue
        }
    }
}

let studentNumber = StudentNumber(numbers: [
    [1, 2, 3, 4],
    [1, 2, 3, 4],
    [1, 2, 3, 4]
    ])


let number = studentNumber[1, 2]

extension

いつも使っているので真新しいことはなかったが、使い方や使う時の考え方、注意点などが言語化されているのがこの本の良いところだと思う。曖昧な理解なことに気付かされる。エクステンションでstored propertyを定義することができないがそれを解決するためのワークアラウンドはいくつも出てくるが自分は当面使いたくない。

Stored Properties In Swift Extensions - Marco Santa Dev

Swiftのextensionでstored propertyを追加する?(黒魔術は閉じ込める) • Yuta Tokoro

疑問に思ったことはextensionにstored propertyが定義できない理由。書籍にも書いてなくて自分で調べたが確実にこれだというのものは見つけられなかった。

ドキュメント

他にはextensionで既存の型にinitializerを追加することでアプリケーション固有の情報から既存の型のインスタンスを生成するなどがある。initializerを定義するだけなのでコードは貼らない。実務で開発しているアプリでAPIリクエスト投げた時のエラーメッセージを使う時にUIAlertControllerを使っているが、その時に毎回UIAlertControllerを初期化するのは面倒なのでエラー内容をEnumで受け取るconvenience initializerをextensionで定義すると毎回書かなくて済むの楽だ。

型の種類

classとstatic違いと使い分け

その値がサブクラスで変更される可能性があるかどうかで使い分ければ良さそう。staticがつくとoverride出来ないので。 書籍ではその後例としてコードを記載して終わったが、staticとfinal classはどう違うのか気になってしまった。 staticとclassのみ変更した2つのswiftファイルのSILを観て比較してもアクセスの仕方が違うだけでclass funcもstatic funcと同じ関数が用意されていた。今度はfinal funcとclass funcを比較してみると、SILレベルで同じファイルが生成された。つまりclass funcとstatic funcはどっちを使っても良いのではと思った。

自分はここで調べるのを辞めてしまったが、Qittaの記事でclass funcとfinal class funcを比較している記事がありとても勉強になった。 https://qiita.com/YutoMizutani/items/040d8af5bfc38d9f1fac#_reference-173b518dffeeba29ba18

参照型の比較

==しか使っていなかった。参照元の比較が1回で済む所を、一意なプロパティを定義して値で比較していた。

class HogeClass: Equatable {
    static func == (lhs: HogeClass, rhs: HogeClass) -> Bool {
        return true
    }
    var value: String
    init(value: String) {
        self.value = value
    }
}


let hoge1 = HogeClass(value: "hoge")
let hoge2 = HogeClass(value: "hoge")

// 値の比較
hoge1 == hoge2 // true

// 参照の比較
hoge1 === hoge2 // false

protocol

protocol composition

whereで条件指定する時に&は使っているが関数の引数で2つのprotocolにconformしていることを要求したことがあんまりなかった。大抵の場合2つのprotocolにconformしたprotocolを用意してそれを引数にしていたと思う。

protocol HogeProtocol {
    var hoge: String { get }
}

protocol FugaProtocol {
    var fuga: String { get }
}

struct HogeFuga: HogeProtocol, FugaProtocol {
    var hoge: String
    var fuga: String
}

func hogeFugaFunction(x: HogeProtocol & FugaProtocol) -> String {
    return x.hoge + x.fuga
}

let hogefuga: HogeFuga = HogeFuga(hoge: "hoge", fuga: "fuga")
hogeFugaFunction(x: hogefuga)

標準ライブラリのプロトコル

前回読んだ時も思ったが、protocolで1番おもしろいのはここだった。実際に使っている"=="などをprotocolを使ってどのように実装しているか知ることができる。サンプルコードで実際に標準ライブラリのプロトコルにconformした型を定義するので、読んで自分で書いてみながらprotocolの便利さが実感できる。Swift触ったばかりの時はRubyで覚えたOOPしか知らなかったのでprotocolを中心に実装していく利点がいまいちわからなかったのを覚えている。 

ジェネリクス

戻り値からの型推論による特殊化

いつも引数からの型推論による特殊化を行っていたので両方選択肢があった時に戻り値からの型推論による特殊化を採用するイメージがまだ湧かない。property宣言する時に明示的に型を明示したい時とかかなあ。

func getAnyValue<T>(_ any: Any) -> T? {
    return any as? T
}

let a: String? = getAnyValue("abc")
let b: Int? = getAnyValue(2)
let c = getAnyValue("hogehoge") // Generic parameter 'T' could not be inferred

型の設計指針

copy on write

var ids = [1, 2, 3]
var ids2 = ids
ids.append(4)
ids
ids2

idsをids2に代入した時点でコピーが行われているように見えるが、実際はarray1.append(4)の時。違いが生じた時。

その他構造体とクラス、プロトコルと継承の使い分けの基準についての説明等があったが、この点は実務で疑問に思って何度も調べて今の所疑問もないので割愛。

イベント通知

ここで気になったのは細かい所。

#selectorの引数として渡すmethodに@objcをつけないといけない理由

公式のdocumantationに#selectorについての記載がある。

developer.apple.com

SelectorはObjective-CではObjective-Cメソッドの名前を参照する型らしい。Swiftでは、Objective-CのSelectorはSelector strunctで表され、"#selector" 式を使用して構築できる。 "#selector"を使ってメソッドを呼び出す時、Objective-CのMethod dispatchの方式、Messageを使用したdispatchを行うため、@objcが必要になる。数日前にMethod dispatchについて調べたおかげですんなり理解できた。

書籍にもSelector型について説明がある。

セレクタObjective-Cの概念であるため、Selectorgata wo生成するにはメソッドがObjective-Cから参照可能である必要があります。

とのこと

参考

stackoverflow.com

github.com

ja.stackoverflow.com

qiita.com

エラー処理

ここで知りたかったそれぞれのエラー処理のやり方をどのように使い分けるか。そのことが丁寧に説明されている。

do-catch

Result<T, Error>との使い分けの部分勉強になった。Result<T, Error>は型引数Errorと同じ型のエラーしか扱えないのに対し、do-catchではErrorプロトコルに準拠する型であればどのような型でも扱える。それぞれエラーを予測できるResult<T, Error>と複数の種類のエラーを1ヶ所で扱えるdo-catchには明確なメリットとデメリットがあることを理解できた。とはいえ実際のコーディングの時に読んだだけで使えるわけがないのでエラー処理を書くたびにしばらく読み返すことになりそう。

アサーション

一度も使ったことなかった。テストでAssert〜って書くぐらい。

func countHoge(count: Int) -> String {
    var strings: [String] = []
    assert(count >= 5, "引数の数字は5以上に設定してください")
    for _ in 0..<count {
        strings.append("hoge")
    }
    return strings.joined()
}


print(countHoge(count: 5))   // hogehogehogehogehoge
print(countHoge(count: 4))   // Assertion failed: 引数の数字は5以上に設定してください: file ios.playground, line 7

リリース時に無効になるのは良い。たまにprint文が残ったままになっていることがあったので。 

2018年振り返りと2019年の抱負

丸一年プログラマとして働いた

2017年の5月にWebメディア運営を行っていた部署の管理職からプログラマに転職したので2017年は会社にとってほぼ使い物にならない状態だったと思う。 2018年は一年間を通して1つのサービスの開発に携わってApp Storeにリリースすることができ、一通りリリースまで自分一人で経験させてもらえたのは幸運だった。

また、社内で運営しているWordpressで構築したWebサイトの保守と要望対応も行っていた。 プライベートではSwiftを使って年末に急いでパーソナルはてなフィルタを個人用に開発した。とりあえずはプライベートで使えるようになった。

また、ずっとSwiftを書いていたのでよりSwiftらしいコードの書き方にこだわるようになり、Swiftの型システムやジェネリクスプロトコルがどのように実現されているかにも関心を持つようになった。

2019年

  • 今宣伝に向けてアプリのブラッシュアップとデザインの刷新を進めているので春先には完成させて宣伝のフェーズに移りたい。 Wordpressで構築したWebサイトの改善要望への対応はPHPJavaScriptjQueryCSSを扱うが、普段使ってる言語と違って対応が遅くなりがちなのでプライベートでも時間を取って抵抗がなくなるように学習を進めたい。

  • プライベートで作っているアプリの完成度は世に出すのはありえないぐらいのクオリティなので使いながら不満点を改善しつつデザインを整えてApp Storeでリリース出来るように進めていきたい。

  • より良いコードがSwiftで書けるようにもっとたくさんコードを読んで書いていきたい。 Swift言語そのものやコンパイラにせっかく興味を持ったのでまずはわいわいswiftcの動画がYoutubeに公開されているので年始に一通り観てどういう風に学習を進めるか決めていきたい。わいわいswiftc行きたいけど福岡からだと厳しい…。

自作キーボードにハマった

電子工作初心者ではんだ付けも全く経験がない状態だったが、わからないことは調べたり質問させていただきながらいくつかキーボードを組み立てた。キーマップを自由に変更出来るキーボードが手に入ったのは非常に良かった。

いくつか撮影した写真は以下

自作キーボード - works

今の所組み立てたキーボード一覧

  • Ergo42
  • Ergo42 Towel
  • Helix
  • Let's Split
  • Ergodash
  • Planck
  • Lhaplus
  • Fourier
  • crkbd
  • iris

積んでいるキーボード一覧

  • Fortitude60

2019年

キーボードは結構作ったもののキーキャップの味気なさに悲しくなったので最近はキーキャップに関心がある。好みのキーキャップを探して今年は散財していきたい。良い値段のする60%キーボードも2019年には作りたい。

総括と2019年の抱負まとめ

仕事が深刻な状況にあるとプライベートも充実しないタイプなので、自作キーボードだけでなくゲームにも熱中出来た今年は公私共に良い年だったんだと思う。 とはいえ、初心者として入社して多少上がったものの、現職の給与には満足していないので、現職で給与を上げられるように現職で働きながら転職の準備も少しずつ進めていきたい。 2018年、大変お世話になりました。2019年もよろしくお願いします。

Fallout76のメインシナリオを友人と2人でプレイした後の感想

f:id:nabeatsu1:20181231172130j:plain Fallout76を2人でプレイした。きちんとしたレビューは以下の記事などを参照するのが良いと思う。今回書くのはライターでもない1ユーザーがプレイした感想。

arcadia11.hatenablog.com

jp.ign.com

世界観

Falloutの過去作をプレイしていた人ならご存知の魅力的なNPCが今作では一切登場しない。広大なマップにユーザーが放り出されてスコーチやスーパーミュータントしかいない世界を放浪して食料や武器、クラフトの素材を求めて放浪するゲーム。

ロケーション、グラフィックはさらに良くなっていた。ソロでプレイしているときに風景に目を奪われて周りを見渡して雰囲気に浸っていた時間は短くない。拾ったホロテープを再生して終わっていく世界に自分の記録を残そうとしている音声にしんみりしながらカバー版「Country Roads(カントリー・ロード)」を聴いてプレイしていた。

ストーリー

と同時に前作Fallout4のレビューでよく見られたworld feels “empty”という指摘をより強く感じさせられる内容だった。魅力的なNPCが削除され本当のサバイバルになったは良いもののメインのシナリオもサブのシナリオもさらにお使い感が強くなった。2箇所を何度も往復させられ、さらにバグで全く先に進めずロードしなおして単調で長いクエストを周回させられた時は本当に虚しかった。ロードが非常に長いことがさらにストレスだった。

秀逸な世界設定とそれを舞台にした示唆に富んだストーリーと魅力的なキャラクター、勢力にユーザーが選択した行動によって主人公の在り方を定義出来るところが好きだった。

今回のFallout76は過去作の好きだったそういうところをプレイしていてほとんど感じなかった。

エストや世界観にユーザーが関与できる部分は殆どなく、基本的にはお使いを繰り返すだけ。それでもあのFalloutの世界観で友達とプレイするのは非常に楽しい。ただ協力プレイ中に会話やシューティングの部分にばかりフォーカスしてシナリオや雰囲気について考える暇もなくストーリーが進行していったのは惜しいことをしたなと反省している。

オンラインで遭遇する他ユーザーについて

特定の役割をこなすNPC以外は敵しかいない世界観なのでたまに野良のユーザーと遭遇するとお互いにエモートを送り合ってコミュニケーションを取ることが多かった。特にソロでプレイしているユーザーは親切にも資源や武器を落としてくれることもあった。自分もレベルがまだ低い人がいたら積極的に助けたり資源を目の前で落としてあげたりしていた。

また、レベル150ぐらいのユーザーがゴロゴロいるので発売されてそう時間も立っていないのに何時間プレイしているんだと最初は思ったものの理由は簡単だった。というのも、伝説級の武器収集やレベル上げに非常に効率が良い場所がいくつかあり、そこには常に高レベル帯のユーザーが常に集まっている。オンラインゲームではよくあることだ。

クラフト要素や武器について

メインクエストやサブクエストの報酬として、他には各MAPにオブジェクトとして配置されていたり収納箱に格納されていたりするのでそれを回収していくのは今作の醍醐味の一つだと思う。とはいえ、収集しなくても全く問題ないのでシナリオをクリアしたいだけなら気にしなくて良い。収集した素材や武器を収納しておく収納箱の容量はこれから拡大されていく予定らしい。  

買って後悔するようなものではない

バグは多いしロードは遅いし上記のような不満あるもののFallout独特の世界観の中で少ない資源でやりくりしながらクエストをこなしていくのは本当に楽しかった。メインクエストと特定のクラフトアイテムの設計図を手に入れるためのサブクエスト、デイリーのイベントしかやっていないが買う価値は十分にあった。

一通りクリアしたら今度はFactorioをプレイすることになっているのでしばらくプレイしなくなるだろうが、今後MOD対応も予定されているのでその時にまたFallout76を起動したい。