コンピュータ

...now browsing by category

 

[Swift] Arrayのインデックスに範囲外の値を入れてもクラッシュしないようにする

日曜日, 10月 22nd, 2017

概要

配列の要素のアクセスにて、クラッシュする”[]”の代わりに、nilを返す”[safe: ]”を追加して使う方法です。

序文

SwiftではArrayのインデックスに範囲外の値を指定するとクラッシュします。

    let array = ["A", "B", "C"]
    let index = 3
    let item = array[index]  // EXC_BAD_INSTRUCTION でクラッシュ

そのため、要素にアクセスする前に、インデックスのチェックを行う方法があります。

    let array = ["A", "B", "C"]
    let index = 3
    guard array.indices.contains(index) else {
        // インデックスの範囲外なら、nilを返す
        return nil
    }
    let item = array[index]  // 実行されない
}

面倒なのでついついサボって省略してしまい、後でクラッシュすることがあります。

実装

そこで、安全にアクセスできる”[safe: ]”を追加して、”[]”の代わりに使います。
これはインデックスが範囲外の場合、nilを返してくれます。
“[]”(subscript(Self.Index))はCollectionプロトコルのメソッドなので、同様にCollectionプロトコルに追加します。

extension Collection {
    subscript (safe index: Index) -> Element? {
        return indices.contains(index) ? self[index] : nil
    }
}

用例

“[]”の代わりに”[safe: ]”を使うと、インデックスが範囲外でもクラッシュせずにnilを返します。

    let array = ["A", "B", "C"]
    let index = 3
    let item = array[safe: index]  // nilを返す

注意

ちなみに配列の要素にnilが入っていた場合、戻り値の型は”Type??”になります。

    let array = ["A", "B", "C", nil]
    let index = 3
    let item = array[safe: index]  // item : String??

itemに対する最初のunwrapでnilならインデックスが範囲外、2度目のunwrapでnilなら要素がnilです。

    guard let firstUnwrappedItem = item else {
        return nil  // インデックスが範囲外
    }
    
    guard let secondUnwrappedItem = firstUnwrappedItem else {
        return nil  // 要素がnil
    }

追記

「そもそも範囲外のインデックスにアクセスするのはバグなのだから、nilを返すよりクラッシュさせてしまうべき」との意見もあるのですが、ユーザーにとってはアプリがクラッシュするのは最悪の事態なので、クラッシュするよりも動かない(nilチェックでリターンさせているとほとんどこの動きになります)方がはるかに良いと考えてます。

これは組込み系でよくある、フェイルセーフの考え方が主軸になっています。

参考

xcode – Safe (bounds-checked) array lookup in Swift, through optional bindings? – Stack Overflow

AdMob on iPhone X

日曜日, 9月 24th, 2017

自分のアプリをiPhone Xのシミュレーターで表示してみたのですが、AdMobの部分がセーフゾーンに収まらないですね。AdMobをバージョンアップすれば出来たりするのかな?

【追記】
と思ったら、別のアプリだとちゃんとセーフゾーンに収まっている・・・
やはりフレームワークのバージョンかなー。
どこでバージョン見れるんだろう。

【さらに追記】
原因は私のミスでした・・・
ちゃんとセーフゾーンに収まっていたアプリは、AdMobのバナーをStoryboard上で定義していて、ちゃんと下端が Bottom Layout Guide に合うように設定していました。
一方、セーフゾーンからはみ出していたアプリは、AdMobのバナーをソースコード上で定義していて、しかも Autolayout を使わずに、viewController.view.frame の下端に合うように frameを設定していました。

AdMobのバナーをStoryboard上で定義していて、下端が Bottom Layout Guide に合うように設定したところ、セーフゾーン内に収まるように表示されました。

Bose QuietComfort 35 wireless headphones

月曜日, 5月 1st, 2017

以前、通勤中に使っていたBluetooth接続のヘッドホンが壊れたため、新しいのを買いました。

考慮した点

絶対条件として、まずはBluetooth接続であること。以前のもBlutoothだったのですが、コードがないのは本当に便利で、身にしみていました。もうコード付きには戻れません。

次にオーバーイヤータイプであること。純正のようなイヤフォンだと、私の場合、耳からポロポロ落ちてしまうのです。また、前使っていたのはオンイヤータイプだったのですが、時々耳からずれることがありました。そんな中、家で使っている有線のオーバーイヤータイプのヘッドフォンは、外れたりずれたりする事がなく、とても具合が良かったのです。なので、今回は通勤用のヘッドフォンもオーバーイヤータイプにすることにしました。

それとノイズキャンセリング機能です。以前からとても興味があったのですが、購入したことはありませんでした。なので、今回はこれにこだわりました。

競合との比較

そうなるとSONYのMDR-1000Xも気になる所です。こちらも上記の条件を備えていて、値段も同じくらいです。

QuietComfortが良いところは、操作がシンプルであることです。電源のON/OFFはスライドスイッチで、曲のスキップとバックはダブルクリックとトリプルクリックです。対してMDR-1000Xは、電源のON/OFFは長押しで、曲のスキップとバックは専用のボタンです。実は前使っていたヘッドフォンはSONY製なのですが、この点が使いづらかったのです。専用のボタンが多い方が使いやすそうに思えるのですが、確かに目で見て操作する分にはボタンが多い方が使いやすいのですが、目で見ずに手探りで操作する場合はボタンが少ない方が分かり易いのです。特に曲のスキップとバックは、音量ボタンと取りちがえることが時々あり、またスキップとバックどちらが上のボタンだったかもよく忘れていました。

一方でMDR-1000Xの方が優れている点は、ペアリング記憶台数が8台であることです。対してQuietComfortは2台です。音源機器の数が多い場合は大変魅了的なのですが、とりあえずiPhoneとMacにつながればOKだったので、そのあたりは気にしませんでた。

良かった点

何と言ってもノイズキャンセリングがとても優秀です。基本的に通勤電車の中で使っているのですが、在来線が新幹線並みの静かさになります。これを付けていると時間が立つのが早く感じます。やはり静かなのは落ち着くみたいで、通勤がとても楽になりました。音によるストレスって以外に大きかったんですね。

また、静かになった分、音楽も小さな音でも充分に聞こえるので、耳に負担が少ないです。でも車内アナウンスはちゃんと聞こえます。車内アナウンスも音が小さくはなるのですが、走行音ほどは減衰されません。ノイズキャンセリングを周波数によって分けているみたいです。感覚としては新幹線の車内アナウンスくらいの音量です。

いまいちな所

大きくて重い点です。これはオーバーイヤータイプを選んだ時点で覚悟していたのですが、やはり荷物になります。重量はケース込みで400gくらいで、通勤カバンの中ではそれなりの容量と重さです。

あと、静かすぎるので歩きながら使うのは危険です。車が背後から来ても気づかないレベルです。ノイズキャンセリングがOFFにできないのもそれに拍車をかけます。じっと座っていられる環境でしか使ってません。

MacBook Air Mid-2011 バッテリー交換

日曜日, 3月 12th, 2017

友達からMacBook Air Mid-2011を買いました。
ただバッテリーがへたっていて満充電でも1時間くらいしか持ちません。
そこでバッテリーを買って、自分で交換することにしました。

分解の参考にしたのは定番のiFixitのサイトです。
最近日本語化されて便利になりました。

交換用のバッテリーは、純正品はまず出回っていません。なので、サードパーティ製品を探すのですが、結構当たり外れがあるので、信頼できそうで安いのを探します。
最初、iFixitでMacBook Air 11″ (Mid 2011/Mid 2012) Batteryを買おうと思ったのですが、バッテリーは日本に送ってくれないでした。
なので、Amazonでそれなりの値段で評価も悪くないのを探しました。
今回買った交換用のバッテリーはSLODAというメーカーのものです。

まず、テーブルにタオルなどを敷いて、MacBookを裏返してして起きます。

裏蓋を開けたところです。
裏蓋を外すには、特殊工具のMacBookシリースで使われている星型のP5サイズのドライバーが必要です。
5年落ちなので、かなり汚れてますね。
この機会にホコリを払っておきます。
カメラ用のブロアーブラシを使いました。
特に空冷ファンの周りはホコリが詰まっているので、念入りに。

バッテリーの取り外しには、T5のトルクスドライバーが必要です。
こちらはホームセンターとかにも売ってますね。
バッテリーを取り外したところ、5箇所あるネジ穴のうち4箇所が割れていました。
過去に大きな衝撃を受けたのかもしれません。

ホコリも払い、新しいバッテリーに交換し、綺麗になりました。
バッテリーはプラスチック製のトレイにセルが貼り付けられている形状で、楽に交換できます。
このバッテリーは純正品とはセルの形が違いますね。

バッテリー交換後のシステムレポートです。
充放電回数が1回になってます。2ヶ月後に見たら3回でした。
ほとんどACアダプターにつないで使っていることが多いのでアレですが、何%まで減った後に充電したら1回になるのか不明です。
稼働時間は確実に伸びました。
ちゃんと時間を計っていなかったのですが、5時間くらいでした。

私の .exrc または .vimrc

木曜日, 4月 14th, 2016

UNIXではviを使うことが多いです。
ただ、同じ環境でずっと使うよりも、あちこちの環境でちょこちょこ使うことが多く、.exrc(.vimrc)を設定せずにやってしまうこともしばしばです。
なので、知見がなかなか貯まらなかったのですが、ブログにまとめておくことにしました。

"行番号を表示
set number

"タブをスペース4個に設定
set tabstop=4
set shiftwidth=4
set expandtab

"改行時に自動的にインデント
set autoindent

"検索時、文頭と文末をまたがない
set nowrapscan

"長い行を省略せずに全部表示する
set display=lastline

"変換候補メニューの高さ(行)を指定
set pumheight=10

"対応する括弧に一瞬ジャンプする
set showmatch
set matchtime=1

これでインターネットにつながる環境なら、このブログからコピペして使えます。
まあ、仕事だとインターネットに繋がらない現場で作業することも多かったですが。