学生かえるエンジニアのブログ

iOSを主にやる勉強中エンジニア。かえるが好き。ピクルスってかわいいよね。

Storyboard上のNavigationBarのサイズでワーニングがでてる

Storyboard で Navigation Bar (というか Navigation Controller ) を使ってたら Warning がでて、

良くある AutoLayout の本来あるべき位置とのズレとかで出てるやつかと思って update frames しても治らない

特に直さなくても Warning だから実行は出来るし問題はないけど、精神衛生上よくないから消したい。

エラー内容

Frame for “Navigation Bar” will be different at run time.

Xcode 8.3.3

解決策

ViewController の Simulated Size を一度 Freedom にしてから Fixed に戻す

f:id:yuki0n0:20170817111923p:plain

参考

ios - Warning frame for "Navigation bar" will be different at run time appears in XCode 8 Swift 3 - Stack Overflow

後記

最近ラズパイ買ってraspbian動かしたり、virtual boxでubuntu動かしたり、TVチューナー買って遊んだりしてるのでまた記事にできたらいいな。

Swift / 変数・定数(property)編

以前「Optional 〇〇」系の言葉についてまとめた記事を上げてみました。

yuki0n0.hateblo.jp

今回は変数・定数などのpropertyについてまとめたいと思います。

今回は名称だけでなく記述方法等、使い方にも少し踏み込みたいと思います。

Property

下記のようないわゆる変数・定数がありますね。

var name = "yuki"

これをpropertyといいます。これには大きく2種類あります。

Stored Property (保持型プロパティ)*1

var name = "yuki"
let name = "yuki"

これは通常の変数・定数です。

プロパティ監視

var name = "yuki" {
    willSet(newName) {
        print("\(name)から\(newName)に変更するよ")
    }
    didSet(oldName) {
        print("\(oldName)から\(name)に変更したよ")
    }
}

このようにゲッターセッターを備えることが出来ます。 このプロパティ監視は stored property にのみ使用できます。

もし引数を与えない場合、willSet内ではnewValue、didSet内ではoldValueという名前で値が取得できます。

下記に使用条件等を示しておきます。

  • このプロパティ監視は保持型プロパティの変数(var)のみに使用できます。
  • didSet内で自分自身の値を変更すると、上書きされ、この際プロパティ監視は呼ばれません。
  • 後述の遅延評価プロパティ(lazy)には使用できません。

Lazy Stored Property (遅延評価プロパティ)

lazy var human = Human()

先頭にlazyとつけることで遅延評価プロパティとなります。アクセスされるまでインスタンスが生成されないと言うものです。

重いインスタンス生成で、使用されるかわからないプロパティなどに使用すると価値が発揮されます。

  • 保持型プロパティの変数のみに使用できます。
  • 先述のプロパティ監視は使用できません。

Computed Property (計算型プロパティ)

var height: Int = 9
let width: Int = 10
var area: Int {
    set(newArea) {
        height = newArea / width
    }
    get {
        return height * width
    }
}

computed property は、3行目のareaのようなpropertyを言います。名称の通り、計算をするプロパティであり、値は保持しません。

setに引数を与えない場合、set内でnewValueという名前で値を取得できます。

  • varだけ使用できます。(letは使用しません。)
  • 型を指定しなければいけません。(stored propertyのような型推論は無いです。)

read-only computed property

var area: Int {
    return height * width
}

もし computed property でgetのみを使用する場合、get{}は省略できます。こうすることでreadonlyなプロパティとなります。

参考

後記

夏休みになりました。

もし間違い等ありましたらコメントなどで教えてください。感想なども待ってます!

*1:格納型プロパティとも呼ばれるそうです

ゆうちょダイレクトのお客さま番号を半自動入力

ブラウザにIDパスワードを保存する機能がありますよね。これのおかげで頻繁にアクセスする会員制のサイトでもストレスなく使用することが出来ます。

しかし、ゆうちょ銀行の場合、はじめにお客さま番号とかいう4桁-4桁-5桁意味不明な番号を求められます。

こんなの覚えてられるか。

自動入力してくれ。

そんな気持ちにお答えして、普段自分が使っている自作のブックマークレットを紹介しましょう。

※当記事により発生した損害等の責任は一切負いかねます。
ブックマークレット上に書くだけなのと、このお客さま番号だけでログインできるわけではないので過度に心配する必要はないと思いますが、万が一不正アクセスに成功された場合送金などを許すことになるのを念頭に置きましょう。

使い方

1. ブックマーク作成/追加

ブラウザでブックマーク(お気に入り)を作成して下さい。

よくわからなければ、このブログをブックマーク(お気に入り)に追加して下さい。

2. URL欄を書き換える

1.で作成したブックマークのURLの欄を消し、下記コードをコピペして下さい。

このとき、このコードの中の上4桁, 中4桁, 下5桁と書いてある所は自分のお客さま番号に書き換えてください。

javascript:(function() {var focus1 = document.getElementById('focus1');var focus2 = document.getElementById('focus2');var focus3 = document.getElementById('focus3');focus1.value = "上4桁";focus2.value = "中4桁";focus3.value = "下5桁";})();

ブックマークの名前の欄は「お客さま番号入力」など好きな名前に書き換えてください。

3. 使う

あとは使うだけです。

ゆうちょダイレクトのログインページに行き、普段ブックマークしたサイトを開くのと同じように、先程作成したブックマークをクリックします。

問題がなければ入力欄に自分の番号が入力されているはずです。

コードの説明

説明するまでもないコードですが一応。

お客さま番号の各値はタグのidがfocus1~3だったので、そこに自分のお客さま番号を代入してます。

javascript:(function() {
    var focus1 = document.getElementById('focus1');
    var focus2 = document.getElementById('focus2');
    var focus3 = document.getElementById('focus3');

    focus1.value = "0000";
    focus2.value = "0000";
    focus3.value = "00000";
})();

後記

GWですね。うん。

Swiftの言葉・名称の理解 (if-let 構文など「Optional〇〇」)

独学で学んでいると、

「書けるけど名称がわからない」

「だから困ったときに検索しづらい」

「エンジニアとの会話で言いたいことが言えない・相手の発言が理解できない」

こんなことがよくあります。言葉を理解しようということで、Optional系の言葉をまとめてみました。

Forced Unwrapping フォーストアンラッピング

var str: String?
print(str!)

上記のように!をつけてオプショナル型を強制的に非オプショナル型にします。

もしstrnilだった時落ちてしまうため、いかなるときもあまり推奨されません。

Nil Coalescing Operator ニルコレーシングオペレーター

var str: String?
let unwrapStr = str ?? ""

[1.オプショナルな値] ?? [2.左と同じ型で非オプショナルな値] こう書くことで、

もし1がnilの時は2が、もし1がnilで無い時は1が返り、かつ非オプショナル型で返ります。

上記の例でいくとunwrapStrは非オプショナルな通常のString型であり、safetyなコードとなります。

if文や三項演算子nil判定などすると可読性が失われたりコードが冗長になるので、この書き方はスマートで好きです。

Optional Binding オプショナルバインディング

var str: String?

if let unwrapStr = str {
    print(unwrapStr) // unwrapStrはオプショナルではない
}
// この場所でunwrapStrは使えない

str! などするのは、例えnilで無いことが確実であっても少し嫌。そんなときに書く出番も多いこの書き方ですね。

単純に if-let 構文 といったりもするようです。

guard-let 構文 (guard との併用 )

この書き方も多いです。この書き方はインデントが深くならない所が魅力的です。

この記事は名称把握のためであって技術的解説が目的ではないので細かくは割愛します。

guard let unwrapStr = str else {
    // strがnilの時 (この場所でunwrapStrは使えない)
    return
}
// この場所でのunwrapStrは非オプショナル型

Shadowing シャドーイング

これは同じ名前の変数を宣言する的な事でしょう。

例えば関数の引数をいじりたい時、直接はいじれないので同名の変数を宣言してから扱います。

func foo(i: Int) {
    var i = i
}
// func foo(var i: Int) という書き方はswift3から出来なくなりました。

先程の Optional Binding の時にもつかえて、下記の様に使います。

この書き方のほうが頻出でしょうね。

var str: String?

if let str = str {
    print(str) // この場所でのstrは非オプショナル
}
// この場所でのstrはオプショナル

Optional Chaining オプショナルチェイニング

class Fruit {   
    var name: String
    func cook() -> String
}
var fruit: Fruit?

let fruiteName = fruit?.name
// fruit がnilの場合、fruiteName は nil
// そうでない場合、通常の値がオプショナル型で返る

let food = fruit?.cook()
// fruit がnilの場合、cook関数は実行されず、foodはnil
// そうでない場合、cook関数は実行され、通常の値がオプショナル型で返る

上記のように、オプショナルのプロパティやメソッドを、?で繋ぐことでOptionalChainingとなります。

これにより、fruitnilか否かを事前に判定する必要などもなくsafetyにコードを書くことが出来ます。

ただ、返る値がオプショナルになります。

参考

どこよりも分かりやすいSwiftの"?"と"!" - Qiita

【Swift】オプショナルバインディングでネストを避ける - Qiita

var a = a や if let b = b {} のような紛らわしい構文も使えるswiftのシャドウイング - Qiita

swift-evolution/0003-remove-var-parameters.md at master · apple/swift-evolution · GitHub

【Swift】Optional型を安全にunwrapしよう - Qiita

後記

間違いや追加情報などありましたらコメントお願いします!

感想やご意見などもぜひぜひ!

Swiftで付属型enumを比較するとき

enumを比較する時、switchifを普通に使いますよね

大抵の場合はうまくいくんですが、付属型enum*1が含まれるとifでの比較がうまくいかなかったりします!

そんな時の書き方!

通常パターン

よく見る何もついてない普通のenumをswitchはうまくいく。

enum Mode {
    case special, normal, other
}
let mode: Mode = .special

// ビルド成功
switch mode {
case .special: break
default: break
}

// ビルド成功
if mode == .special {}

付属型enumパターン

次に1つだけ付属型enumにしてみましょう。

switchの比較では問題なくいきますが、if文ではエラーになります。

しかも、付属型にしたのはotherでありspecialは何もついていないのにビルドは通りません。

enum Mode {
    case special
    case normal
    case other(name: String)
}
let mode: Mode = .special

// ビルド成功
switch mode {
case .special: break
case .other: break
default: break
}

// エラー
if mode == .special {}

解決策

1. if文の書き方を工夫する

このように書きます。=は2つではなく1つです。

いっつもこの書き方を忘れるw

しかもこの書き方検索しても日本語記事が全然見つからない!

// 付属型enum を含む enum と比較する場合
if case Mode.special = mode {}
// 付属型の値を利用したい場合
if case let Mode.other(name) = mode {}

2. enumに関数を用意する (1.の書き方を忘れた場合)

1.での書き方を忘れたパターン。けどいちいちswitch文を書いてると行数が多くなり可読性が下がります。

そんな時はswitch比較をenum内で行いましょう。

enum Mode {
    case special
    case normal
    case other(name: String)
    
    // 関数を用意する
    func isSpecial() -> Bool {
        switch self {
        case .special:
            return true
        default:
            return false
        }
    }
    
    // get-only プロパティ版 (上記と同じ事)
    var isSpecial: Bool {
        switch self {
        case .special:
            return true
        default:
            return false
        }
    }
}

if mode.isSpecial {}

補足

switch文で付属の値を使用したい時は下記のように書きます。

switch mode {
case .other(let name):
    break
}

参考

Advanced & Practical Enum usage in Swift

後記

(Obj-Cから)swiftになりenumが便利になったとよく聞きます。try! Swift ではenumの話ばっかりだったとか。

それに加え自分の中ではswitch文もとても良くなったなと思っています。比較可能なものが増えインデントも同じになり、比較方法も色々かけ、、、

またこのブログでも分かる範囲でまとめていきたいなと思います。

間違い、追加情報等ありましたらコメントなど頂けますと幸いです。

try! Swift いきたいなぁ…

*1:関連型enum, Associated Value ともいう

Xcodeにベクタ画像(pdf)を追加してもジャギる(iOS開発)

iPhoneの種類が増えるにつれ、各解像度にあわせて @1x @2x @3x の画像を用意するようになりました。

そしていつからだか、Xcode(iOS)がベクタ画像 *1 に対応しましたね。

「やったー!これで用意する画像1つだけでいいじゃん!」

と喜びつつも、実際に使用してみると

「ジャギるじゃん!(怒)」

そんなデザイナーエンジニアのみなさん!

原因が判明しました!

実は

「ベクタ画像に対応した」
「 ベクタ画像がそのまま使用され、どの解像度でも綺麗に表示される 。」
→ 「 ベクタ画像をもとにラスタ画像を生成し、従来 *2 と同様に扱われる。 」

ということでした。

100 x 100 pximage.pdf という画像を用意したとすると、ビルド時に下記ファイルが生成される。

ファイル名 サイズ
image.png 100 x 100 px
image@2x.png 200 x 200 px
image@3x.png 300 x 300 px

結論

  • ベクタ画像(PDF)をセットすると、ビルド時にXcode@1x @2x @3xPNG画像が生成されて使用される。

  • PDFを使用する場合は、@1x の時に必要なサイズでPDFを書き出して使用する

参考

xcode 8 import pdf (vector) intro image assets not working well - Stack Overflow

How do vector images work in Xcode (i.e. pdf files)? - Stack Overflow

後記

最低週1くらいは更新できたらいいな。

技術的なこと書くと下調べが面倒臭いからこういう記事になっちゃう。

*1:ただしPDF形式のみ。

*2:ベクタ画像が対応されていなかった時代

自作UIViewに@IBDesignableを適用してもうまくいかない問題

自作UIViewに@IBDesignableを適用して、StoryboardやXibファイルで使用しようとしたらビルドがうまく通りませんでした。

原因は、自作のUIViewをXibを使用して作る時の、Xibを読み込むコードに問題が有りました。

解決策

下記コードではなく、

Bundle.main.loadNibNamed("ファイル名", owner: self, options: nil)?.first as? UIView

下記のコードでXibを読み込みます。

Bundle(for: type(of: self)).loadNibNamed("ファイル名", owner: self, options: nil)?.first as? UIView

参考

ios - @IBDesignable error: IB Designables: Failed to update auto layout status: Interface Builder Cocoa Touch Tool crashed - Stack Overflow

後記

高校時代にGoogleBloggerで技術ブログをやってたんですが、はてなブログはマークダウンで記事がかけて楽しいですね笑

なにか間違いや補足、感想などあればコメントお願いします!