読者です 読者をやめる 読者になる 読者になる

Think Big Act Local

iPhone開発を軸にブレブレの記事を書いていきます。

「売れるもマーケ 当たるもマーケ マーケティング22の法則」を読んだ

読書メモ マーケティング

売れるもマーケ 当たるもマーケ―マーケティング22の法則

売れるもマーケ 当たるもマーケ―マーケティング22の法則

この本は過去に実際にあったマーケティングの話をベースに、「こうしなければいけない」「こうしちゃうと死ぬ」みたいな法則をまとめている本です。一部ではマーケティングの教科書とも呼ばれているみたいです 。

自分は以前から「似たような機能をもったプロダクトは沢山あるのに、なぜこのプロダクトだけが流行るのか?」を不思議に思っていて、マーケティング系の本はたまに読んでたんですが、この本は自分の持っていた疑問の多くを解決してくれた気がします。

とても良い本だったので、自分の頭の中を整理する意味も込めてまとめてみます。

続きを読む

ユーザーの声に耳を傾けてアプリを改善するサービス「Meyasubaco」をつくりました

iOS Android Meyasubaco

f:id:himaratsu:20160602223737p:plain meyasuba.co

自分がアプリ開発を行っているときに考えてるのが「この機能とかUIはアプリのユーザーに伝わっているのかな?」ということです。

どれだけ良い機能でもユーザーに使われなければ意味がない。だからユーザーの気持ちになって考えることは常に意識してるのですが、これがとても難しいです。自分はIT業界にいて色んなアプリを触ってるし、機能について考えまくってるのでユーザーと同じ目線をなかなか持ちにくいんですね。

なので、これまではアプリに仕込んだイベントログからユーザーの行動を推測していました。自分はGoogle Analyticsを使ってるのですが、それを見て

  • 「あーこのボタンは気付かれてないな」
  • 「この画面に来たら意味がわからなくて離脱してるな」
  • 「この機能を使ったユーザーはアプリを気に入ってくれる確率が高いな」

みたいに予想を立てて、それを解決/強化する機能改善を行ってまた反応を見る、みたいな感じです。

これは結構良いのですが、ちょっと自分的には不満があって、もっとユーザーの定性的なコメントも知りたいな、と思いました。「めっちゃ便利です!!やばい!!!!」みたいなのも知りたいなぁと。

そんなわけでアプリのユーザーと直接会話ができて、感想や要望を手軽に聞いたりできる「Meyasubaco」というサービスを作りました!

Meyasubaco

meyasuba.co

Meyasubacoは「ユーザーの声を聞いてアプリ改善していこう」というサービスで、iOS/Androidに対応しています。

機能としてはユーザーと直接会話できる「チャット機能」と、よくある質問を表示する「ヘルプ機能」の2つがあります。
2~3行の短いコードを書くだけですぐに使い始められるのが特徴です。

セットアップ

iOSを例にします (Androidの手順ははこちら

// Podfile
pod 'Meyasubaco'

$ pod install

CocoaPods経由でiOS SDKをダウンロードして、以下のコードを書けばセットアップ完了です。

// AppDelegate.swift
Meyasubaco.setApiKey("{YOUR_API_KEY}")

チャット機能

チャット機能は、ユーザーとLINEのようなチャットインターフェースで会話できる機能です。
実装は簡単で、チャット画面を表示したい任意のタイミングで以下のコードを呼びます。

Meyasubaco.showCommentViewController(self)

するとアプリ側ではこんなフォームが表示されます。

f:id:himaratsu:20160602094504j:plain:w300

ユーザーが要望や意見を入力して送信すると、デベロッパー向けのダッシュボードにはこんな感じで表示されます。

f:id:himaratsu:20160602195634p:plain:w580

ここからユーザーに返信すると、アプリ側がチャットインタフェースになって、会話ができるようになります。

f:id:himaratsu:20160602094828j:plain:w300

重要なのは デベロッパーがダッシュボードから返信しない限りチャットインタフェースにならない という部分で、「来たコメントに全部返事書くの大変すぎる…。でも返信しないと感じ悪いし…」とならなくてすみます。
普段は要望コメントを受け付けだけしておいて、より深く聞きたい場合のみ、ユーザーに詳しく聞くことができるのです。

ヘルプ機能

ヘルプ機能は、ユーザーにFAQを表示できる機能です。
ダッシュボード上から入稿したヘルプをアプリ上に表示することができます。

Meyasubaco.showHelpListViewController(self)

するとアプリ側では以下のように表示されます。

f:id:himaratsu:20160602095137j:plain:w300

ここに表示されるヘルプはダッシュボードから更新できるので、アプリ自体をアップデートする必要がありません。

アプリを更新するのは色々と大変(パッケージを作る手間や、iOSだと審査があったりレビューがリセットされる等)なので、ポチポチやるだけで更新できるこの機能は自分的に重宝しています。

また、ダッシュボードでは各ヘルプごとの閲覧数がわかるので、「あ、ユーザーはこの使い方が分かりにくいんだな。次回のアップデートでここを強化しよう」などの方針を決めるのにも役立ちます。

f:id:himaratsu:20160602200407p:plain:w560

というわけで

数行のコードでアプリのユーザーと対話できる「Meyasubaco」というサービスをつくった話でした。
お値段は登録後3ヵ月無料で、さらに3ヵ月経っても一部の機能(返信機能など)に制限がかかるだけでアプリが使えなくなるなどはありません。自分のアプリのユーザーと、手軽に話してみたいな、という方はぜひ試してみてください:)

meyasuba.co

最後になりましたが、 Meyasubaco は会社の同僚と3人で、プライベートな時間で開発してます。まだまだな部分も多くあると思いますが、機能が足りないとか使い勝手が悪いなどあれば、寛容な精神で微笑みながら厳しくフィードバックしてくれると喜びます!

初級者から中級者にレベルアップするためのXcodeデバッグ術

iOS Xcode デバッグ 開発効率

効率よくiOSアプリ開発を行うために、効率よくデバッグを行いたいですよね。

このエントリでは「print文を書く以外デバッグの方法を知らなかったあの頃の自分」を初級者と定義して、自分がやってるデバッグ方法について書いてみます。

Xcodeデバッグ

1. printを使わずに変数の中身を確認する

age, name, coverImage という以下の3つの変数が宣言されています。

let age = 27
let name = "Ryosuke Hiramatsu"
let coverImage = UIImage(named: "sample.jpg")

これらの変数の中身をチェックしたい時、printで出力するのでも良いですが、それでは出力する値を変えたくなった時(print(age)print(age*2+1)に変更とか)に再度ビルドが必要になって時間がかかります。

printではなく、LLDBコマンドを使って確認することができます。

f:id:himaratsu:20160325214853p:plain

こんな感じで Breakpoint を貼って*1、そこで処理を止めた状態で Console に以下のように入力します。

(lldb) po age
27

(lldb) po name
"Ryosuke Hiramatsu"

単純に変数の値を出力するだけではなく、式の評価もできます。

(lldb) po age+1
28

(lldb) po name.characters.split(" ").map{ String($0) }.first
"Ryosuke"

2. QuickLookを使ってUIImageの中身を確認する

coverImage 変数に対して、printやpoコマンドではどんな画像なのか確認できません。

let coverImage = UIImage(named: "sample.jpg")
// print(coverImage) とした時のコンソール出力
Optional(<UIImage: 0x14fe19460>, {640, 640})

こういった場合、変数の上にマウスカーソルを合わせ、

f:id:himaratsu:20160325215318p:plain

現れたポップアップの目のアイコンをタップすることで画像が確認できます。

f:id:himaratsu:20160325215428p:plain

変数の値や画像の表示は、Xcodeの左下のAreaからも可能

変数の確認や QuickLook による画像の確認は Console の左のエリアからも可能です。

age や name などの変数名の横に値が出ていて一目で確認できます。

f:id:himaratsu:20160325215632p:plain

coverImage を選択した状態で目のアイコンをクリックして画像を表示することも可能です。

f:id:himaratsu:20160325215706p:plain

単純な変数の確認であればこちらの方が便利ですね。

3. 自作クラスのdescriptionをカスタマイズする

例えば以下のようなクラスを作ったとします。

class Person {
    let name: String
    let age: Int
    let coverImage: UIImage?
    
    init(name: String, age: Int, coverImage: UIImage?) {
        self.name = name
        self.age = age
        self.coverImage = coverImage
    }
}

以下のようにPersonクラスのインスタンスを生成します。

let person = Person(name: name, age: age, coverImage: coverImage)

このインスタンスのプロパティを確認しようと思ってprint(person)としてみると、Consoleには以下のように表示されます。

// print(person)
XcodeDebugPractice.Person

これは知りたい情報ではありません。LLDBでpo person.nameなどとすれば確認はできますが、少し手間がかかります。
こういうシーンではクラスのログ出力をカスタマイズしましょう。

CustomStringConvertibleを使う

先ほどの Person クラスを編集して、以下のようにします。

class Person: CustomStringConvertible { //★
    let name: String
    let age: Int
    let coverImage: UIImage?
    
    init(name: String, age: Int, coverImage: UIImage?) {
        self.name = name
        self.age = age
        self.coverImage = coverImage
    }
    
    //★
    var description: String {
        return "\(name), \(age)"
    }
}

この状態で再びprint(person)するとコンソールには以下が出力されます。

Ryosuke Hiramatsu, 27

description で指定した値が出ています。CustomStringConvertibleは print などで出力される値をカスタムするために用意されている Protocol です。

さらに、CustomStringDebugConvertible Protocol にも準拠してみます。

class Person: CustomStringConvertible,
    CustomDebugStringConvertible {  // ★
    // ... 省略 ...    
    var description: String {
        return "\(name), \(age)"
    }
    
    var debugDescription: String {  // ★
        return "\(name), \(age), \(coverImage)"
    }
}

CustomStringDebugConvertible はpoコマンドなどでデバッグプリントする際の値をカスタムできるものです。

他にも CustomReflectableCustomLeafReflectableCustomPlaygroundQuickLookable などが用意されていますので興味のある方は調べてみてください。

4. Breakpointをカスタマイズする

Breakpoint をもっと便利に使いましょう。例えば Loop で特定の条件の時だけ止めたかったり、あるいは処理は止めずに Breakpoint を通過したら Console にログを吐きたい、というような場面があるとします。そんな時には Breakpoint のカスタマイズが便利です。

例えばこんな感じのループ文を用意して試してみます。

for i in 0...50 {
    print(i)
}

ブレイクポイントを右クリックして「Edit Breakpoint」を選択し、

f:id:himaratsu:20160325221924p:plain

conditionに条件を入れます。今回は「i==22の時のみ止まる」ように設定してます。

f:id:himaratsu:20160325221955p:plain

この状態で実行すると、i==22のループの時のみ Breakpoint で処理が止まります。特定条件の時に変数の値を確認したい場合などに便利ですね。

おまけ:ブレイク時に音を出してデバッグする

Breakpoint では「ブレイク時にどんなOutputをするか」もカスタム可能です。

例えば「i==22の時だけ変数の値を確認したい。でも処理は止めずに続けたくて、値の内容は音声で確認したい」という場合は以下のように設定します。

f:id:himaratsu:20160325222529p:plain

これで実行すると「22 hit!」という音声が(おそらくsayコマンドで)発声され、下の「Automatically continue after evaluating actions」にチェックをつけているため処理は止まらずに継続されます。

いろんな特殊条件で発生する不具合を調査する際など、Condition をうまく使うことでデバッグを効率的に行うことができます。ちなみに自分は実プロジェクトで音声デバッグを使ったことはありませんw

5. アプリ内に保存したデータを確認する

NSUserDefaults や Document ディレクトリなどに保存したデータの中身を確認する方法です。
例えば以下のコードで値や画像を保存したとします:

// NSUserDefaultsに値を保存
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject("@himara2", forKey: "account")
defaults.synchronize()

// Diskに画像を保存
if let path = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .AllDomainsMask, true).first,
  coverImage = coverImage {
    let targetPath = path.stringByAppendingString("/sample_data.jpg")
      if let data = UIImageJPEGRepresentation(coverImage, 0.5) {
        let success = data.writeToFile(targetPath, atomically: true)
        print(success)
      }
}

保存されたデータを確認してみます。

Xcode > Window > Organizer と選択して Organizer を開きます。

f:id:himaratsu:20160325223309p:plain

左メニューでアプリを実行したデバイスを選択して、対象のアプリを選択します。

f:id:himaratsu:20160325223343p:plain

設定ボタンから「Download Container...」を選択し、適当な場所に保存します。

f:id:himaratsu:20160325223425p:plain

xcappdata 拡張子のファイルが保存されますので、右クリックして「パッケージの内容を表示」します。

f:id:himaratsu:20160325223607p:plain

中身はこのようになっています。
Documents/ に保存した画像ファイル(sample_data.jpg)が存在しているのが分かります。

f:id:himaratsu:20160325224142p:plain

さらに、Library/Preferences/ 下のplistの中身をみると、

f:id:himaratsu:20160325224304p:plain

このように NSUserDefaults の値が保存されていることが分かります。

保存した内容を取り出すコードを実装するのでも良いのですが、ハマった時は原因が切り分けが大事なので、実際に保存されている情報を目視できるのは意味のあることだと思っています。

まとめ

Xcodeデバッグ手法に関する記事は以外と少なく、自分が最初にアプリ開発を始めた時は NSLog を大量に埋めて頑張ってました。
今回紹介したようなデバッグ手法を知ってからスピーディに開発できるようになったな、と思ったのでこのような記事を書かせていただきました。

何か間違ってる部分や、他に良いデバッグ方法などご存知でしたらぜひ教えてください :)

みなさんのデバッグライフに少しでもお役立ちできれば光栄です。

サンプルコード

github.com

今回引用したコードはすべてこちらでお試しいただけます。

こちらもいかがですか?

himaratsu.hatenablog.com

himaratsu.hatenablog.com

*1:Breakpointは行番号のあたりをクリックで設定/解除できます

XcodeのPlaygroundをつかってUIの実装をサクサク試す

iOS Swift trySwift 開発効率

Xcode の Playground を久しぶりに使ってみて、UIの実装とかこれでやると便利だな、と思ったのでやり方をまとめてみます。

やりたい完成系はこんな感じ:

左に書いた TableView のコードが右で即時反映されてます。

前置き:そもそもPlaygroundとは

f:id:himaratsu:20160318235944p:plain

Playground というのは Xcode 6 から登場した Swift の REPL 環境です。
上記の画像のように、コードを書くと実行結果がビルドすることなしに即時に表示されます。Swift の文法を試せすのにもってこいで、自分も入門したての頃にはよく使ってました。

Apple の公式の Swift ドキュメント「The Swift Programming Language」の概要部分ではドキュメントが Playground として実装されていて、実際に値を変えたり動かしながら確認することができます。(ここのページの Download Playground から落とせます)

f:id:himaratsu:20160319000548p:plain

実際に動かせるドキュメントとして Playground はとても優秀で、読んで→書いてとやってたのが同時に可能です。最近流行りのOSSライブラリであるRxSwiftでもPlayground形式のドキュメントが同梱されたりしています。

PlaygroundでUIをつくる

3月頭に try! Swift というSwiftのカンファレンスに参加したんですが、そこで驚いたのが海外のスピーカーの方がよく Playground を使ってることでした。
文法のデモはもちろん、アニメーションの調整(モンスターボールを投げると回転して爆発してポケモンが登場する)や TableView の実装まで、Project ではなくて Playground でサクサクと進めてました。

自分は最近はほとんど Playground 使ってなくて、どれくらい便利なのかなーと思って試してみたやり方と感想をまとめます。

XCPlaygroundをimportする

下記のように記述して、XCPlayground を import します。

import XCPlayground

ライブ表示するviewを指定する

次に右側にライブ表示する view を指定します。
今回は UITableViewController を root とした NavigationController を表示するので、以下のように指定します。

let tableVC = UITableViewController()
let navigationController = UINavigationController(rootViewController: tableVC)

XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
XCPlaygroundPage.currentPage.liveView = navigationController.view

Assistant Editorを開く

viewはREPLで表示されるコンソールではなく、Assistant Editor で開いた Timeline に表示されます。

f:id:himaratsu:20160319011142p:plain

ここまでで view が表示できてるはずです。

実装を書いていく

試した内容としては、カスタムな UITableView を書いて、その view を Playground でライブ表示していきました。
Playground につらつらと書いていって、以下のように記述しました。

import UIKit

final class MyTableViewController: UITableViewController {
    // ... MyTableViewControllerの実装をここに
}

let tableVC = MyTableViewController(style: .Plain,
    items: people,
    cellStyle: .Subtitle,
    editable: true)     { cell, item in
        cell.textLabel?.text = item.name
        cell.detailTextLabel?.text = item.city
    }
tableVC.title = "Person"
let navigationController = UINavigationController(rootViewController: tableVC)

navigationController.view.frame = CGRectMake(0, 0, 320, 480)

import XCPlayground

XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
XCPlaygroundPage.currentPage.liveView = navigationController.view

こんな感じで書いていくと、以下のように表示されます。

f:id:himaratsu:20160319002149p:plain

いい感じですね!

コードを修正するたびに変更が右側のViewに反映されていくので、とても効率よく実装ができます。

サンプルコード

今回試した内容はこちらのリポジトリにまとめています。

github.com

Xcode 7.2, Swift 2.1 でつくりました)

まとめ

Playground で UI を実装するのはとても快適でした。ビルド時間はいらないし、「ビルドするぞ」と切り替える回数が少ないのも捗ります。
現在はタッチイベントなどは検知できませんが、次の Xcode のバージョンでは UITapGestureRecognizer などにも対応するようで、それができると一気に可能性が広がる気がします。

一方で、storyboard とか xib を使っての実装とは相性はよくありません。try! Swiftのスピーカー陣は storyboard 使わない派の人が多かったので、ここは気にしてないのかもしれませんね。
自分は storyboard 積極的に使ってく派ですが、アニメーションや View の部品をコードだけで実装するケースでは今後 Playground で作ろうと思いました。

Xcode Playground は文法の確認やインタラクティブなドキュメントだけでなく、UI の実装にも便利そうという話でした。 みなさまの Playground Life のお助けになれば光栄です :)

try! Swiftで特に復習したいセッションまとめ #tryswiftconf

iOS Swift 勉強会 trySwift

3月2-4日の3日間、try! Swift に参加してきました。

try! Swift とは東京渋谷で開催された、世界中から集まった Swift デベロッパーが知識や技術を共有することを目的としたカンファレンスです。

try! Swift

セッションの内容は自分にとって難しいものが多く、明日から使える tips & tricks みたいなのは少なくて、プログラミング言語の中でSwiftはこういう特性があるよ、そしてそれを活かしてこんなこともできるよね!みたいな、Swiftそのものの話や言語のポテンシャルに言及するものが多かった気がします。

振り返り勉強したいセッション

一度聞いただけでは全然理解できてない

そんな濃いセッションだったので、一度聞いただけでは2割も理解できてないです。
そこで、個人的に振り返って勉強したい順にセッションをまとめてみます。

業務やプライベートの実際のプロダクトで試すのが一番理解が進められると思ったので、そういう意味での試しやすい順番に並べました。

1.既存のコードをもっとSwiftyにする系セッション

会社ではフルSwiftで書いてるけど、まだまだ言語の特性を活かせる箇所が多く見つかったので。

Blending Cultures

Table View Controllers in Swift

Hipster Swift

2.デバッグやテストをしっかり学ぶ系セッション

特にテストはいまあまり書けてないので重点的に復習したい。

Swift compiler integration in LLDB

An Artsy Testing Tour

Protocol-Oriented Programming in Networking

3.ワンランク上にレベルアップできそうなセッション

普段コードを書くときに心がけることで、メンバーや未来の自分に意図が"伝わる"コードを書ける。

The Design of Everyday Swift

本も読んでみる。

誰のためのデザイン? 増補・改訂版 ―認知科学者のデザイン原論

誰のためのデザイン? 増補・改訂版 ―認知科学者のデザイン原論

Learning to Read Again

4.OSSを公開/貢献する系のセッション

今年は自分の使ってるモジュールを切り出して公開していこうと思っているので。

Creating a Library

Motivation based library abstraction

Contributing to open source Swift

  • OSSのなったSwift、その概要を理解し、自分が貢献できそうな領域を見つけよう、という話
  • 前半の解説部分、後半の貢献へのスタンスとコミュニティの話、どちらも最高でした
  • 自分でOSSをいくつか公開した後、Swift のコードをよく読んでみたい
  • 参考リンク

感想・全セッションを通じて思ったこと

  • サーバーサイド Swift の話がよく出ていくる
    • 日本ではそんなにまだ聞かないな?と思ってたので驚いた
  • みんな簡単なコードやプロトタイプくらいは Playground で書いている
    • 自分も真似してちょっと使ってみたけど大変便利。今後も使っていきたい
  • テストについてはみんな悩んでいる
    • テストのセッションの最後のQAで、「テストの工数をどう理解してもらえるか」「UIテストをどう考えてるか」という質問が出て、万国共通の悩みなんだなと思った
    • Twitterにあった「テストコードを書くことで、テストが書ける状態にリファクタリングされるのが大事」というのが自分の考えに近い
  • Protocol Extension, Functional Programming が頻出
    • 意識して使えてなくて、Objective-Cy なコードを書いてしまってるなぁ、と反省
  • 本質的な話が多かった
    • こんなライブラリがありまして、みたいな話はほぼなくて、すべてに共通する考え方・実装の仕方の話が多かった
    • 「明日からこのライブラリ使うぞ!」とはならず、「自分の普段書いてるコードはどうなのか」と振り返る機会になった

まとめ

3日間とても熱く濃い時間をすごせました。

普段ほとんど Swift を書いてるのに理解できない話がとても多く、悔しい思いもしましたが、これをエネルギーにしてひとつずつキャッチアップしていこうと思います。

スピーカーのみなさま、運営スタッフのみなさま、そして素晴らしい会場を提供してくださったサイバーエージェントさん、本当にありがとうございました!