トップ 追記

Cocoa練習帳

iOS/iPhone/iPad/watchOS/tvOS/MacOSX/Android プログラミング, Objective-C, Cocoa, Swiftなど

2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|

2018-09-15 [cocoa][swift]AppleScriptとは何ぞや

スマートフォン・エンジニアにとって、macOSはOfficeが動くUNIXという利点があり、シェル・スクリプトを利用した自動化に威力を発揮している。ただ、macOSにはMacintosh時代からのAPpleScriptがあり、これを利用しない手はない。
自動化したけど、アラートが表示されていて失敗したという悲しいトラブルも、これで回避できるかも!?

シェルスクリプトとして実行する

#!/usr/bin/osascript
display dialog "Welcome to AppleScript."

シェルスクリプトからAppleScriptをよぶ

#!/bin/sh
osascript -e 'display dialog "Welcome to AppleScript."'

AppleScriptからシェルスクリプトを呼ぶ

set fileInfo to do shell script "cd ~; ls" 
display dialog fileInfo 

最前面のアプリを終了させる

#!/usr/bin/osascript
 
tell application "System Events"
    set fullname to name of (path to frontmost application)
end tell
 
set savedDelimiters to AppleScript's text item delimiters
set AppleScript's text item delimiters to "."
set front_app to items 1 thru -2 of text items of fullname as text
set AppleScript's text item delimiters to savedDelimiters
 
if front_app is "Firefox" then
    tell application "Firefox"
        quit
    end tell
end if

最前面のアプリのダイアログを改行キーで閉じる

#!/usr/bin/osascript
 
tell application "System Events"
    set fullname to name of (path to frontmost application)
end tell
 
set savedDelimiters to AppleScript's text item delimiters
set AppleScript's text item delimiters to "."
set front_app to items 1 thru -2 of text items of fullname as text
set AppleScript's text item delimiters to savedDelimiters
 
if front_app is "Firefox" then
    tell application "System Events"
        keystroke return
    end tell
end if

2018-09-14 [cocoa][swift]Web API通信の符号化について(ASN.1, JSON, MessagePack, ProtocolBuffers, FlatBuffers, Avro)

本発表では、Web API 通信の基本と符号化について説明する。

HTTP通信
Web API通信とは、Webブラウザでホームページを閲覧する際のHTTP通信と同じ物だ。サーバから得られた結果を文書としてWebブラウザで表示するか、プログラムで利用する為のデータを取得するかの違いでしかない。
Webブラウザのアドレス欄に、「http://www.bitz.co.jp/index.html」と入力すると、Webブラウザはサーバに対して以下の要求を送る。

GET /index.html HTTP/1.1
Host: www.bitz.co.jp
Accept: image/pict, image/postscript, */*
Accept-Language: en
Connection: Keep-Alive
Uset-Agent: ave-front/1.0

すると、サーバは、以下の応答を返す。

HTTP/1.1 200 OK
Date: Sat, 25 Aug 2018 23:40:00 GMT
Server: Apache/1.3.9 (Unix)
Last-Modified: Fri, 24 Aug 2018 09:30:00 GMT
ETag: “12345-123-12345678”
Content-Length: 141
Content-Type: text/html
 
>html<
	>head<>title<INDEX>/title<>/head<
	>body<
		本文
	>/body<
>/html<

途中の空行より上がヘッダー部、下がボディ部となる。
Webブラウザは、応答のボディ部のデータを表示している。
Web API通信では、ボディ部に符号化されたデータが格納されることになる。

ASN.1
通信のデータ構造、エンコード、デコードを記述する記法で、たとえば、SNMPで利用されている。RSA公開鍵を生成する必要があって、ASN.1の知識が必要になったことがあったが、その際、調べた事を説明する。
RSA公開鍵は、modulusとpublicExponentの二つのパラメータで構成されている。他のプラットフォームでは、この二つのパラメータからRSA公開鍵を生成するAPIが用意されていたのだが、iOSでは用意されていなかったので、独自に対応した。
RSA公開鍵のASN.1での定義は以下のとおり。

RSAPublicKey ::= SEQUENCE {
    modulus INTEGER, -- n
    publicExponent INTEGER -- e
}

ASN.1のエンコード方式は複数あるのだが、RSA公開鍵はDERということなので、これについて説明する。
SEQUENCEやINTEGER等のオブジェクトの形式は以下のとおり。

タグ 長さ

タグの番号は以下のとおり。

タグ タグ番号 説明
INTEGER 0x02 整数型
SEQUENCE 0x10 構造体 / 配列

オブジェクトのタグ欄には、タグ番号がそのまま格納されるのではなくて以下の形式となっている。

8 7 6 5 4 3 2 1
クラス
00: 汎用
構造化フラグ
タグ番号

7〜8bitのクラスは、汎用型のSEQUENCEとINTEGERのみなので、RSA公開鍵では00となる。
6bitの構造化は、INTEGERは単一型(0)、SEQUENCEは構造型(1)となる。なので、タグ欄にはINTEGERにはタグ番号そのものが設定され、SEQUENCEは、00+1+10000=0x30となる。
長さ欄は、以下のとおり。

8 7 6 5 4 3 2 1
0 長さ(127オクテット以下)

8bitに収まらない場合は以下となる。

8 7 6 5 4 3 2 1
1 長さ部の長さn
8 7 6 5 4 3 2 1
トークン1

・・・

8 7 6 5 4 3 2 1
トークンn

JSON
JSONは、JavaScriptのオブジェクトの表記法をベースとした軽量なデータ記述書式で、人にとっての読み書きしやすいのが特徴だ。

{
    "name" : "Pear",
    "points" : 250,
    "description" : "A ripe pear."
}

CocoaでJSONを扱うために以前からJSONSerializationというクラスが用意されていたが、その後追加されたJSONEncoderとJSONDecoderを利用すれば、JSONの扱いもより一層簡単になる。
以下は、構造体からJSONデータを生成するサンプルだ。

struct GroceryProduct: Codable {
    var name: String
    var points: Int
    var description: String?
}
 
let pear = GroceryProduct(name: "Pear", points: 250, description: "A ripe pear.")
 
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
 
let data = try encoder.encode(pear)
print(String(data: data, encoding: .utf8)!)

以下は、逆にJSONデータから構造体のインスタンスを得るサンプルだ。

let json = """
{
    "name": "Durian",
    "points": 600,
    "description": "A fruit with a distinctive scent."
}
""".data(using: .utf8)!
 
let decoder = JSONDecoder()
let product = try decoder.decode(GroceryProduct.self, from: json)
 
print(product.name) // Prints "Durian"
print(product)

MessagePack
MessagePackはJSON感覚で利用できる符号化の仕組みで、公開されて仕様をもとに本家以外からも各種環境のライブラリが提供されている。どの符号化方式を選ぶから、クライアント側の都合のみではダメで、サーバ側の環境向けのライブラリが用意されているかが重要だ。この条件に合致するMessagePackはJSONの次に採用される符号化の資格が十分あるが、我々Cocoaプログラマにとっての不満は、Objective-C / Swift のライブラリが充実していないということだ。
なので、軽く触れる説明するにとどめる。

{ “compact”:true, “schema@:0 }

これをMessagePackで符号化すると以下のとおり。

[82][A7]compact [C3][A6]schema [00]
[82]
2-element map
[A7]compact
7-byte string
[C3]
true
[A6]schema
6-byte string
[00]
integer 0

バイナリ書式なので、27bytesから18bytesに短縮。

ProtocolBuffers
インタフェース定義言語(IDL)で構造を定義する符号化方式で、大規模なプロジェクトの場合、仕様書からIDLを出力し、IDLで定義した内容でクライアントとサーバが通信するという利点がある。
Googleが開発したものだが、本家からObjective-C / Swiftのライブラリが提供されていないという欠点があったのだが、なんと、Appleから提供されるようになった!

例。定義ファイル (.proto ファイル) を用意する。

syntax = "proto3";
 
message BookInfo {
   int64 id = 1;
   string title = 2;
   string author = 3;
}

Swiftコードを生成する。

$ protoc --swift_out=. DataModel.proto

これを利用してエンコード / デコードする。

// Create a BookInfo object and populate it:
var info = BookInfo()
info.id = 1734
info.title = "Really Interesting Book"
info.author = "Jane Smith"
 
// As above, but generating a read-only value:
let info2 = BookInfo.with {
    $0.id = 1735
    $0.title = "Even More Interesting"
    $0.author = "Jane Q. Smith"
  }
 
// Serialize to binary protobuf format:
let binaryData: Data = try info.serializedData()
 
// Deserialize a received Data object from `binaryData`
let decodedInfo = try BookInfo(serializedData: binaryData)
 
// Serialize to JSON format as a Data object
let jsonData: Data = try info.jsonUTF8Data()
 
// Deserialize from JSON format from `jsonData`
let receivedFromJSON = try BookInfo(jsonUTF8Data: jsonData)

FlatBuffers
これもGoogle製の符号化方式で高パフォーマンスが特徴だ。
ただ、本家からObjective-C / Swiftライブラリが提供されていないので紹介するにとどめる。

Apache Avro
これも本家からObjective-C / Swiftライブラリが提供されていないということで、簡単な紹介にとどめる。
ProtocolBuffersと比較される符号化方式となるが、特徴なのはC#がサポートされていて、Unityで利用できるということ。これで採用されているプロジェクトがあるようだ。


2018-09-13 [cocoa][swift]Cocoa.swift 2018-10のご案内

次回勉強会の案内です。

開会から名称が、Cocoa.swift (Cocoa勉強会 関東 Swift分科会) と変わります。今後、池袋以外での開催を考えているのと、Cocoaといえば、この勉強会と認知されているので、それを名称にしました!


■ 第115回 Cocoa勉強会 関東 のご案内
日時:
2018/10/17(水) 19:30-22:00
会場:
池袋コワーキングスペース OpenOffice FOREST
http://co-forest.com
集合:
現地
座席代:
夜間ドロップイン 一人1,000円

■出欠の登録

以下のconnpassサイトからお願いします。
https://cocoa-kanto.connpass.com/event/101034/


[スケジュール]
18:00  自習
19:30  自己紹介
20:00  発表
- 20:00〜20:15 「募集中」未定
- 20:15〜20:30 「募集中」未定
- 20:30〜20:45 「募集中」未定
- 20:45〜21:00 「募集中」未定
- 21:00〜21:15 「募集中」未定
- 21:15〜21:30 「募集中」未定
- 21:30〜21:45 「募集中」未定
21:45  次回日程の決定、片づけ
22:00  解散

2018-08-12 [cocoa][swift]Cocoa.swift 2018-09のご案内

次回勉強会の案内です。

秋に特別な勉強会の開催を検討しています。各自取り組んでいることをしっかりと発表できる場になればと考えています。場所も何時もの池袋以外を考えているのですが、このタイミングで勉強会の名称の修正を考えています。

Cocoa勉強会 関東 Swift分科会ということで、Cocoa.swiftでどうでしょうか?

今後も池袋以外での開催の可能性があるとうことで名称に場所を含めない。そして、Cocoa勉強会の分科会ということでBUKUROをCocoaに差し替える。ご意見がある方は、九月の勉強会でお聞かせください。


■ 第114回 Cocoa勉強会 関東 のご案内
日時:
2018/09/12(水) 19:30-22:00
会場:
池袋コワーキングスペース OpenOffice FOREST
http://co-forest.com
集合:
現地
座席代:
夜間ドロップイン 一人1,000円

■出欠の登録

以下のconnpassサイトからお願いします。
https://cocoa-kanto.connpass.com/event/97193/


[スケジュール]
18:00  自習
19:30  自己紹介
20:00  発表
- 20:00〜20:30 「募集中」未定
- 20:30〜21:00 「符号化について」村上幸雄
  ASN.1, JSON, MessagePack, ProtocolBuffers, FlatBuffers, Avro
- 21:00〜21:15 「募集中」未定
21:15 モブプログラミング
- Master-Detail App を実装する(モデルをどう持つ?etc)
21:30 秋の大勉強会について考える
21:45  次回日程の決定、片づけ
22:00  解散

2018-07-25 [cocoa][swift]BUKURO.swift 2018-07に行ってきた

会場はいつもの池袋コワーキングスペース Open Office FOREST。前回の勉強会は新生MOSA始動のイベントだったので、通常の勉強会は久しぶりだ。

_ VirtualBoxへのMojaveのインストール

VirtualBoxへmacOS Mojaveをインストールするという発表だが、MojaveはUSB1.1コントローラがサポートされていないのと、インストール時にフォーマットをAPFSに変更してしまうのだが、VirtualBoxがAPFSからの起動をサポートしていないという問題があり、それを回避する内容だ。

_ 通信デバッグ

Remote Virtual Interfaceを使って、Macに接続されたiOS端末をMacのターミナルで動かしたtcpdumpでパケット・トレースするという内容だ。

_ SwiftのOptionalを理解する

Swiftでプログラミングする範囲で必要なoptional関連の構文とサンプルコードをスライドにして、それを参加者と内容を確認していくといった内容だ。

_ 構文糖衣なしでSwiftのオプショナルを使うとどうなるか?

前の発表を踏まえて、Optionalの内部での定義を紹介して、より深く理解するという内容だ。

予定していた『モブプログラミング』は時間切れとなり次回以降の実施となった。

秋に田町のコワーキングスペース 森永ヴィレッジで、特別な勉強会の開催が発表されたのだが、現状、勉強会の名称が統一されていないのと、池袋以外での開催となるので、新たな名称として『Cocoa.swift』の提案があった。

より詳細な内容については、FacebookのCocoa勉強会 関東のグループで行うことになったので、是非、意見をいただければ。


2018-07-13 [モブプログラミング]Master-Detail App を実装する

勉強会初の試みとして、モブプログラミングに挑戦します。事前に用意した内容を公開します。

進め方

  • 大まかな仕様があるので、それを参考にして皆で製作する。
    • スムーズにするため、サンプル・プロジェクトを用意する。
    • プロジェクトは共有した方がいいが大変なので、各自ローカルの環境でとする。
  • 役割は、一人がドライバ、その他がナビゲータ。
  • ドライバーは時間を決めて、順番に交代して担当する。時間は例えば5分。
  • ドライバーは操作しているMacの画面を投影して、皆で見ながら進める。
  • 大まかな仕様とサンプルと異なる実装方法の意見があると思うが、それを皆で共有して議論したいので、異なる意見は大いに歓迎。

作るもの

  • iOSのMaster-Detail App。
    • ほぼ、新規プロジェクトで生成される雛形のまま。
  • モデルのクラスを用意する。
    • サンプルのモデルのクラス名は、Document。
    • シングルトンでなく、AppDelegateのメンバー変数で保持。
Example

_ ソースコード

たたき台となるExampleを共有ディスクで公開しています。
Exampleプロジェクト

2018-07-08 [Swift]SwiftのOptionalを理解する

  • Lispでは、無を表すものとしてnilを用意。
  • C言語では、空ポインタとしてNULLマクロを定義。
  • Objective-Cでは、空idとしてnilが用意され、画期的なのはnilにメッセージを送信しても無視されるだけでエラーにならない!
  • SwiftのnilはObjective-Cとの互換。Cocoaフレームワークを利用するためか。
var a : Int = 1
var b : Int? = 2
a = nil  // エラー
b = nil  // OK
b = Int(“abcd”)  // nil
var c : Optional = 3  // パラメータ付き型指定

開示(unwrap)

var a : Int? = 1234
var b : Int = a - 2  // 型が異なるのでコンパイル・エラー
var b : Int = a! - 2  // 開示指定する
a = nil
b = a! - 2  // 実行時エラー
 
a = 5678
if a != nil {
    print(“\(a!)”)  // 開示指定が必要
}
print(String(describing: a))  // Debug目的で

オプショナル束縛構文 optional binding

var num : Int? = 1234
if let n = num {
    print(“\(n)”)
}
 
if var n = Int(“1234”) {
    n += 5678
    print(“\(n)”)
}
 
if let n = Int(“1234”), let m = Int(“5678”) {
    print(“\(n + m)”)
}
 
var a : Int? = 1
while let n = a {
    a = nil
}

guard文

guard 条件 else { /* breakやreturn */ }
 
func demo(_ num:Int?) {
    guard let n = num else { return }
    print(“\(n)”)  // 変数nが使える
}

nil合体演算子

let n : Int? = 1234
 
let m = (n != nil) ? n! : 0
let m = n ?? 0
 
let a : Int? = nil
let b : Int? = nil
let c : Int? = 3
let = a ?? b ?? c ?? 0  // cの値
func demo(_ p: inout Int?) {
    p = nil
}
var n: Int? = 1234
demo(&n)
print(n ?? “nil”)
 
func test(_ num: inout Int) {
    num = 0
}
n = 5678
test(&n!)  // nがnilだと実行時エラー
print(n ?? “nil”)

有値オプショナル型 (IUO)

let n : Int! = 1234
print(“\(n)”)  // 開示指定は不要
 
var m : Int! = nil
m += 5678  // 実行時エラー
print(“\(m)”)

失敗のあるイニシャライザ

struct Demo {
    var a = 0
    init?(_ n:Int) {
        if n < 0 {
            return nil
        }
        a = n
    }
    init() {
        a = 1234
    }
}
var p: Demo = Demo()
var q: Demo? = Demo(5678)

キャスト演算子

  • 式 is T

    型/プロトコルTなら真
  • 式 as T

    型/プロトコルTにキャスト
  • 式 as? T
    型/プロトコルTのオプショナルにキャスト
    失敗した場合はnil
  • 式 as! T
    型/プロトコルTにキャスト
    失敗した場合は実行時エラー

オプショナルチェーン optional chaining

// 辿っている途中でnilがあれば、
// そこで止まり全体でnilとなる。
if let name = who?.club?.teacher?.name {
    print(name)
}

2018-07-07 [iOS]通信デバッグ

最近、iOS端末のパケット・キャプチャでデバッグしたので、その情報をまとめた。

Appleからの情報は、Technical Q&A QA1176 Getting a Packet Traceだ。

Remote Virtual Interfaceの準備と解除の手順は以下のとおり。

# 端末の識別子を調べる。

・Macに端末をUSBで接続する。
・Xcodeを立ち上げ、Window / Devices and Simulators を選ぶ。
・端末のIdentifier: の値を選択してコピーする。

# 端末をつなぐ。

・Terminal.appで以下のコマンドを叩く。
 $ rvictl -s 端末の識別子
 Starting device 端末の識別子 [SUCCEEDED] with interface rvi0

# 端末を外す。

・Terminal.appで以下のコマンドを叩く。 
 $ rvictl -x 端末の識別子

リモート仮想インタフェースの確認

$ ifconfig -l

lo0 gif0 stf0 XHC20 en0 p2p0 awdl0 en1 en2 bridge0 utun0 utun1 utun2 pktap0 en4 rvi0

HTTPSのキャプチャの例。

$ sudo tcpdump port https -I rvi0

RFCからオープンとクローズのパケットの流れを抜き出す。

      TCP A                                                TCP B
  1.  CLOSED                                               LISTEN
  2.  SYN-SENT    -->                --> SYN-RECEIVED
  3.  ESTABLISHED <--   <-- SYN-RECEIVED
  4.  ESTABLISHED -->        --> ESTABLISHED
  5.  ESTABLISHED -->  --> ESTABLISHED
          Basic 3-Way Handshake for Connection Synchronization
      TCP A                                                TCP B
  1.  ESTABLISHED                                          ESTABLISHED
  2.  (Close)
      FIN-WAIT-1  -->   --> CLOSE-WAIT
  3.  FIN-WAIT-2  <--       <-- CLOSE-WAIT
  4.                                                       (Close)
      TIME-WAIT   <--   <-- LAST-ACK
  5.  TIME-WAIT   -->       --> CLOSED
  6.  (2 MSL)
      CLOSED
                         Normal Close Sequence

2018-06-10 [WWDC18]OpenGLとOpenGL ES、OpenCLがdeprecated

いつかその時が来ることは予想されていたが、macOSでOpenGLとOpenCLがdeprecatedとなった。また、iOSでもOpenGL ESがdeprecatedとなった。Metalが推奨されるようになたっということだ。

Khronos GroupからVulkanが発表されたことを考えると時間の問題だったともうが、このタイミングとたった。ただし、推奨されないが使えるので、直ぐに切り替えないとというわけではないが、ゲーム関連のディベロッパーなどは喧喧諤諤としていると思う。

macOSやiOSでMetalとVulkanの関係がどうなるのか予測できない部分もあるが注目していこうと思っている。

_ ●●●

WWDCに行かなかった(行けなかった)、日本残留組の朗報だ!6月15日(金)にWWDC関連の合同勉強会『THe Bash in Tokyo』を開催するので、都合がつく人はぜひ!


2018-05-23 [Automatism]アプリ設計のパターン(機能設計)

どうコードを記述するか?この問題に対するアプローチは様々だ。

書籍『Effective ○○』を参考にする。デザインパターンに乗っ取る。コーディング・ルールに従う。どれも有益だとは思うが、今回は、自分がアプリケーション・プログラマに転身した際に参考にした、『iOS開発に置けるパターンによるオートマティズム』を現在の環境で取り組んでみる事にした。

今回取り上げるのはアプリ設計のパターンだ。

_ # 機能設計

今回、この記事を執筆するにあたって過去の教科書的なプログラム開発技法の書籍を読み返してみて気がつくのは、機能設計に相当することがほとんど触れられていないことだ。どんなサービスを開発するのかはユーザの問題で、技術者はユーザからの要求をいかに文書化するかが需要。また、既存のユーザ作業を図にしていくか、制作するプログラムを処理の図にしていくことが主な関心となっていた。

そういう状況から、iPhoneアプリケーションの開発から始まった、幅広い意味のデザインがアプリケーションを製作するエンジニアに期待される状況に変わっていったのは、画期的なことだったのだろう。

そういう訳で機能設計についてはよく使われる図式のようなものなく、様々な図式の技法で育ってきたプログラマにとって不安に感じる部分なのだが、そんなものは不要ということなのだろう。

それではやってみよう。GTDのような個人のワークフローを管理するiOSアプリケーショの機能設計を行ってみる。まずは機能の列挙だ。

  • 個人のワークフローを管理する。
    • 仕事を入力する。
      • 名称
      • 期限
    • 仕事のリストを並べ替える。
    • 仕事をするタイミングを伝える。
      • 通知を表示する。
    • 完了した仕事を済みにする。
      • 指定されて仕事をリストから削除する。

このアプリではデータをバックアップするとか他機器と同期するとかを考えないと、通信の機能は使わないで実装できそう。通知はローカル通知でいけそうだ。


トップ 追記