ごんれのラボ

iOS、Android、Adobe系ソフトの自動化スクリプトのことを書き連ねています。

2018年振り返り

2018年もお世話になりました

2018年もいろいろな方にお世話になりました。
この場を借りてお礼申し上げます。
今年は自分の中で大きな出来事がいくつかあったので、振り返ってみます。
順不同で、登場順に意図はないです。

転職

転職してました。
猫のいる会社から猫のいない会社へ。

大間知さんのJS講座の講師

大間知さんのJS講座の講師のピンチヒッターも今年の出来事でした。
大間知さんは私のDTPスクリプト人生において、とてもお世話になった方で、いまでもお世話になり続けています。
その恩返しが少しでもできていたら良いのですが。
さて、感想として、人に伝えることの難しさを改めて痛感しました。
でも楽しかった。
この講座をきっかけにもくもく会にも初心者の方が毎回参加してくださって、嬉しい限りです。

DTPスクリプトの受託開発

もくもく会に参加してくださった方からお仕事を二件いただきました。
どんなスクリプトを納品したかについては後日公開予定です。
二つのスクリプトともワークフローや使い方、オペレーションの手順などもスクリプトと一緒に提案させていただきました。
また、あとで編集しやすいように、関数ごとにコメントをつけたり、いろいろ工夫してみました。
担当者様にも満足いただけて、我ながらいいものが納品できました。
来年も引き続きお仕事募集中です。

PEAKSのiOS技術書の編集

PEAKSは一冊目のiOS 11 Programmingを購入してからずっとサービスのファンでした。
そんなことを編集長の永野さんあてにTwitterで言っていたりしたら、なんと「編集してみませんか」と声をかけていただきました。
その場で「やります!」って返事をして、早速今年以下の二冊の編集を手がけました。

peaks.cc

peaks.cc

『iOS 12 Programming』は絶賛発売中で、『iOSアプリ設計パターン入門』はクラウドファンディング(以下、CF)出資者の方のお手元に届き始めたところなので一般発売はもう少々お待ちください。
『iOSアプリ設計パターン入門』は有志(著者含め)が勉強会を開催されることになっていますので、CF購入者の方はご参加いただけると嬉しいです。

iOSアプリ設計ナイト
【朝活】「iOSアプリ設計パターン入門」勉強会 by UZUMAKI #2

来年もいろいろな本に関わっていきたいと思っていますので、PEAKSのCFで気になるものがある方はぜひぽちっとお願いします。

レノくん入院

一番疲弊した出来事がこれです。
三年ぐらい前にかかったことのある下部尿路疾患が再発してしまい、おしっこが出なくなり、がんばっておしっこしようとした結果膀胱炎も併発していました。
結果的に一週間入院させて一旦経過観察という状況です。
下部尿路疾患は完治はしないらしく、ご飯を療法食にして、うまく付き合っていくしかないそう。
療法食がとても太りやすいので、いま彼は7.4キロ以上あります…。
でも元気いっぱい、食欲いっぱい、甘えん坊全開。

入院中は毎日お見舞いにいきました。
だって父ちゃんか姉ちゃんがそばにいないとご飯食べないんだもん…。
初めてお見舞いにいったときに声をかけたら、「父ちゃん…?ほんとに…?父ちゃん?父ちゃん!ご飯!ご飯食べます!」とすりすりもせずにご飯を食べていました。
それでもいいんです、元気なら。
退院後はなぜか猫が変わったように妻や義母に甘え、たくさん遊ぶようになりました。
毎日父ちゃんとかくれんぼと追いかけっこをしています。
あと妻を母猫と思うことにしたらしく、リビングにいるときはクッションに座る妻の膝の上でまったりしてます。
ええ、もちろん膝から盛大にはみだしていますが、とても満足げに寝ているので、父ちゃんも幸せです。

DTPerのスクリプトもくもく会

上述しましたが初心者の方が毎回参加してくださり、積極的に質問していただけるので、活気満ちたもくもく会になっています。
共同主催の id:id:uske_S には感謝しかないですね。
そして第10回はいまだかつてない盛況ぶりで、一度予約していた会場をキャンセルして、新たに大きな会場を借りるという嬉しい悲鳴をあげました。
参加者の熱意がありがたいです。
来年はもくもく会参加者向けのGitハンズオンを開催したいなーと思っているので、気になる方は手をあげてください。
参加者数がわからないと企画立てられないので。

人生二回目の福岡の地

まじで最高だった。
飛行機、興味がまったくなかったんだけど、いざ乗ってみたらフラップの動きとかかっこよくて見入ってました。
飛行機は耳栓必須ということがわかったので、次回行くことがあれば事前に買っておきます。

まとめ

来年もいろいろと新しいことをやっていきたいです。
いろいろなところに顔をだしていくつもりなので、お会いした方はよろしくお願いいたします。
それではよいお年を!

InDesignでMacにインストールされたフォントのフォント見本をほぼ自動で作りたいというSOSを、ExtendScriptで解決のお手伝いをした

概要

お世話になっている方がTwitterでSOSを出されていたので、ExtendScriptで解決のお手伝いをした。

仕様

  • InDesign上のすべてのテキストフレーム内のテキストにMacにインストールされたフォントを適用して、PDFとJPEGを書き出す
    • PDFとJPEGはフォント名で書き出される
  • 実行時に表示されるダイアログに入力された文字列をキーに、フォント名で絞り込みする
    • 正規表現で検索できる
    • なにも入力しない場合はフォント名での絞り込みは行われない
  • PDFに埋め込めないフォントは除外する
  • 以下の形式のフォントは除外する
    • OCF
    • Type1
    • TrueType
  • 欧文フォントと和文フォントの種別判断を行っていないので、日本語に欧文フォントを適用するとアラートが表示される
    • InDesignの設定で無視することを想定しているが、実行後に設定をもとに戻すことを強く推奨する

使い方

  1. InDesignドキュメントにテキストフレームを作成して、テキストを入力する
  2. スクリプトを実行する
  3. 表示されたダイアログで検索したいフォント名の一部分を入力(なにも入力しなくもていい)してOKをクリック
  4. 保存場所を聞かれるので、選択する。デスクトップを選択するとファイルで埋め尽くされるので、フォルダを作成することを強く推奨
  5. 処理が完了すると4のフォルダ内にPDFとJPEGが作成されている

動かしてみるとこんな感じ。

output

ソースコード

まとめ

喜んでいただいてよかった!

Adobe XDのアートボードをPNGに書き出すPluginを作った

概要

2018年10月よりAdobe XDのPlugin開発が誰でもできるようになった。
そこで、公式のサンプルを読み解きつつ、ドキュメント内のアートボードをPNGに書き出すPluginを作ってみた。

仕様

  • 用途に応じて、メニューから「選択しているアートボードを書き出す」「すべてのアートボードを書き出す」を選べる
  • 書き出しサイズは以下のサイズから選べる
    • 0.5x(50%)
    • 1x(100%)
    • 1.5x(150%)
    • 2x(200%)
    • 3x(300%)
    • 4x(400%)
    • 5x(500%)
  • 書き出したPNGはダイアログで選択したフォルダ内に 20181126101110 というような名前のフォルダを作成し、その中に格納される
    • 実行後に表示するアラートに保存先が表示される
  • PNGはアートボード名で書き出される

使い方

output

インストール方法

  1. こちらからxdxファイルをダウンロード
  2. ダウンロードしたxdxファイルをダブルクリック
  3. Pluginをインストールするか確認する旨のダイアログが表示されるので、インストールを選択
  4. インストール完了した旨が表示される
  5. メニュー>プラグイン に「export-artboards-to-png」が表示され、利用可能になる

アンインストール方法

  1. メニュー>プラグイン から「プラグインを管理...」を選択
  2. サイドバーから「インストールされたプラグイン」を選択
  3. 「export-artboards-to-png」にマウスカーソルを合わせると、名前の右側に「…」が表示されるので、クリック
  4. アンインストールを選択
  5. Pluginがアンインストールされる

困ったこと

ドキュメント上のすべてのNodeを取得する方法がわからない

コマンドに渡される第二引数の documentRoot がドキュメント上のすべてのNodeだった。

ドキュメントより抜粋。

Typically, you access scenegraph nodes via the selection argument that is passed to your plugin command, or by traversing the entire document tree using the documentRoot argument that is passed to your plugin command.

option タグで selected をサポートしていない

ダイアログ表示時にデフォルトで書き出しサイズを設定しておきたかったんだけど、ドキュメントにサポートしていない旨書いてあって諦めた。
他に方法があるかもしれないけど…。 ドキュメントはこちら

ソースコード

GitHubで公開しているので、詳しくはそちらを参照してほしい。
export-artboards-to-png

main.js だけ載せておく。

const application = require('application');
const fs = require('uxp').storage.localFileSystem;
const { Artboard } = require('scenegraph');
const {alert, confirm, prompt, error, warning} = require("./lib/dialogs.js");

let selectedRatio;

async function exportSelectedArtboards(selection, root) {
    let nodes = selection.items.filter(node => node instanceof Artboard);
    if (nodes.length == 0) {
        error('エラー', 'アートボードを1つ以上選択して実行ください');
        return;
    } else {
        exportArtboards(nodes);
    }
}

async function exportAllArtboards(selection, root) {
    let nodes = root.children.filter(node => node instanceof Artboard);
    if (nodes.length == 0) {
        error('エラー', 'アートボードが存在しません');
        return;
    } else {
        exportArtboards(nodes);
    }
}

async function exportArtboards(nodes) {
    const outputFilePaths = await exportNodes(nodes);
    if (undefined == outputFilePaths) {
        return;
    }
    const joinedFilePath = outputFilePaths.join('\n');
    alert('処理が完了しました', `書き出したPNGファイルは下記に格納されています\n\n${joinedFilePath}`);
}

async function exportNodes(nodes) {
    const dialog = await makeSelectScaleDialog();
    await dialog.showModal();
    dialog.remove();

    if (selectedRatio.selectedIndex < 0) {
        return;
    }

    const excutedTimeStr = getNowYMDHMS();
    const selectedFolder = await fs.getFolder();
    if (null == selectedFolder) {
        return undefined;
    }
    const folder = await selectedFolder.createFolder(excutedTimeStr);

    let renditions = await makeRenditionOptions(nodes, folder);
    application.createRenditions(renditions)
        .then(results => {
    })
    .catch(error => {
        console.log(error);
    })

    // 書き出したファイルのパスを配列に格納
    const outputFilePaths = renditions.map(rendition => {
        return rendition.outputFile.nativePath;
    });

    return outputFilePaths;
}

async function makeRenditionOptions(nodes, folder) {
    let renditions = [];
    await Promise.all(nodes.map(async (node, i) => {
        const file = await folder.createFile(node.name + '.png', {overwrite: true});
        renditions.push({
            node: node,
            outputFile: file,
            type: 'png',
            scale: selectedRatio.options[Math.max(0, selectedRatio.selectedIndex)].value
        });
    }));
    return renditions;
}

function getNowYMDHMS() {
    const dt = new Date();
    const y = dt.getFullYear();
    const m = ('00' + (dt.getMonth()+1)).slice(-2);
    const d = ('00' + dt.getDate()).slice(-2);
    const h = ('00' + dt.getHours()).slice(-2);
    const mm = ('00' + dt.getMinutes()).slice(-2);
    const s = ('00' + dt.getSeconds()).slice(-2);
    const result = y + m + d + h + mm + s;
    return result;
}

function makeSelectScaleDialog() {
    const labelWidth = 75;

    const dialog =
        h("dialog",
          h("form", { method:"dialog", style: { width: 380 }},
            h("h1", "Select the export scale"),
            h("label", { class: "row" },
              h("span", { style: { width: labelWidth } }, "Scale"),
              selectedRatio = h("select", {  },
                                h("option", { selected: true, value: 0.5 }, "0.5x"),
                                h("option", { value: 1 }, "1x"),
                                h("option", { value: 1.5 }, "1.5x"),
                                h("option", { value: 2 }, "2x"),
                                h("option", { value: 3 }, "3x"),
                                h("option", { value: 4 }, "4x"),
                                h("option", { value: 5 }, "5x")
              )
            ),
            h("footer",
              h("button", { uxpVariant: "primary", onclick(e) { selectedRatio.selectedIndex = -1; dialog.close(); } }, "Cancel"),
              h("button", { uxpVariant: "cta", type: "submit", onclick(e){ dialog.close(); e.preventDefault; } }, "OK")
            )
          )
        )
    document.body.appendChild(dialog);
    return dialog;
}

/**
* Shorthand for creating Elements.
* @param {*} tag The tag name of the element.
* @param {*} [props] Optional props.
* @param {*} children Child elements or strings
*/
function h(tag, props, ...children) {
    let element = document.createElement(tag);
    if (props) {
        if (props.nodeType || typeof props !== "object") {
            children.unshift(props);
        }
        else {
            for (let name in props) {
                let value = props[name];
                if (name == "style") {
                    Object.assign(element.style, value);
                }
                else {
                    element.setAttribute(name, value);
                    element[name] = value;
                }
            }
        }
    }
    for (let child of children) {
        element.appendChild(typeof child === "object" ? child : document.createTextNode(child));
    }
    return element;
}

module.exports = {
    commands: {
        exportSelectedArtboards,
        exportAllArtboards
    }
};

次はなに作るの?

なにかしら通信が発生するものを作りたい。

感想

ES6で書けるの、最高。
InDesignのCEPもES6に対応してくれ!
頼む!!!!!!!!!

参考

公式ドキュメント
はじめてのAdobe XDプラグイン開発!定番のHello Worldを表示させてみよう

FILCO Majestouch MINILA Air US67 Bluetoothキーボードを買いました

良さげなキーボードがほしいと思い続けて幾星霜。
ついに買いました。

購入候補

候補は絞れていて、下記の3機種のどれにしようかと悩んでいました。

購入したもの

REALFORCEもHHKBもとても良いという話を聞いていたんですが、良さげなキーボードを買うのが初めてという状態なので、お手頃価格の FILCO Majestouch MINILA Air US67キー 茶軸 にしました。

ヨドバシ・ドット・コムで購入したら、10時間後に届いてびっくりした。

開封の儀を執り行った

飼い猫レノくんに避けられながら開封の儀を執り行った。

外箱はがっしりしてた。
重量感があってかなりずっしり。

f:id:macneko-ayu:20180924205248j:plain
外箱

思っていたよりコンパクトだけど、高さはそこそこある。
持ち上げてみて「重っ!」っていうぐらいずっしり。持ち運びには向かなそうだ。 キータッチは軽く押しただけで入力ができて、ほどよいカチカチ音で満足。
奥さんからは「やかましいな」とちょっと不評だったけど、負けないぞ。
でも自宅用には赤軸でもいいかも(早速ヒヨる)

f:id:macneko-ayu:20180924205243j:plain
本体

Macbook Proの上に載せてみた。
写真だとキーボードのほうが幅があるように見えるけど、実際はぴったりか少し小さいくらい。

f:id:macneko-ayu:20180924205238j:plain
幅はMacbook Proとほぼ同じくらい

カスタマイズ

DIPスイッチでカスタマイズが可能なんだけど、使ってみた感じでは私は初期状態のままで良さそう。
ただ、WIN キー(Macだと Command)と Alt キー(Macだと Option)の位置が標準キーボードと逆になっているので、そこだけ設定を変えた。
システム環境設定からキーボード設定に遷移して、修飾キー... ボタンをクリックすると、修飾キーの設定を変更するダイアログが表示される。
そのダイアログで CommandOption を入れ替えれば設定完了。

f:id:macneko-ayu:20180924214115p:plain
変更前

f:id:macneko-ayu:20180924214119p:plain
変更後

あと上記の設定変更にあわせて、キートップも入れ替えました。
専用の器具が付属してるので、自他ともに認める不器用の私でも一人でできた!

f:id:macneko-ayu:20180924205233j:plain
購入時のキー配置

f:id:macneko-ayu:20180924205228j:plain
入れ替え後のキー配置

気に入ったところ

少ししか触っていないけど、気に入ったところ。

  • キートップ交換用の器具がついてくる
  • Fnキーがスペースキーの左右にあるので、使いやすい
    • Macbook ProのFnキーはUSキーボードだと左下で押しづらいんだよ…
  • Fnキーとのコンビネーションが便利
    • 矢印キーの代わりになるので、キーボードキー押さなくてよい
    • PageUp、PageDown、Deleteが使えるので便利
  • キータッチがペタペタしてないので良い
    • 入力音が気になると指摘されたけど、Macbook Proのキーボードでも結構うるさいよね

まとめ

良い買い物をした気がする!

iOSでチラシっぽい価格レイアウトを再現してみた

概要

TwitterでフォロワーさんがUIStackViewで挑戦してたのを見かけた。

スレッドを遡ってみると、NSAttributedStringで実装できるんじゃないかという話があり、興味が湧いたので挑戦してみた。

作ったもの

文字のサイズ感は目見当。

chirashi.png

gist.github.com

説明

ソースコードを部分的に切り出して処理内容を説明する。

let fontSize: CGFloat = 80
let font = UIFont.systemFont(ofSize: fontSize)
let attributeText = NSMutableAttributedString(string: "各種¥(税込)280",
                                              attributes: [.font: font, .foregroundColor: UIColor.red])

はじめに attributeText に基本的な装飾と文字列を格納しておいて、装飾を変更したい部分をNSRangeで指定して、加工していく方法をとることにした。

// 各種
attributeText.addAttributes([.font: UIFont.systemFont(ofSize: fontSize * 0.4),
                             .baselineOffset: 2],
                            range: NSRange(location: 0, length: 2))

各種 の部分。
文字サイズは基本サイズの40%の大きさを指定。
や数字よりベースラインが少し下にずれて見えるので、.baselineOffset: 2 を指定して少し上にずらした。
ベースラインについては ラテン文字と欧文組版 をP14の図を参照。
雑に説明すると、.baselineOffset に正の数を与えると上に移動し、負の数を与えると下に移動する。

// ¥
attributeText.addAttributes([.font: UIFont.systemFont(ofSize: fontSize * 0.6),
                             .kern: -50],
                            range: NSRange(location: 2, length: 1))

の部分。
文字サイズは基本サイズの60%の大きさを指定。
.kern: -50 を指定して、次の文字の ( との字間を詰めた。
雑に説明すると、.kern (カーニング)は当該文字と次の文字の文字間のアキを詰める設定。
なお、パーレンにはカーニングが適用されないっぽかったので、を前にもってきてカーニング設定をしている。

// (税込)
attributeText.addAttributes([.font: UIFont.systemFont(ofSize: fontSize * 0.2),
                             .baselineOffset: (fontSize * 0.8) - (fontSize * 0.2) - 4],
                            range: NSRange(location: 3, length: 4))

(税込) の部分。
文字サイズは基本サイズの20%の大きさを指定。
ベースラインは相対値で計算したものの、それだけではうまく揃わなかったので、微調整している。

// ()のベースライン調整
attributeText.addAttributes([.baselineOffset: (fontSize * 0.8) - (fontSize * 0.2) - 3],
                            range: NSRange(location: 3, length: 1))
attributeText.addAttributes([.baselineOffset: (fontSize * 0.8) - (fontSize * 0.2) - 3],
                            range: NSRange(location: 6, length: 1))

() の部分。
ベースラインが揃わなかったので、この部分だけさらに微調整した。

文字列ごとにNSAttributedStringKeyを指定していき、最後に結合する方法でも良かったんだけど、DTP的な手法のほうが手慣れているため、この方法にしてしまったがゆえに、すごくIllustratorやInDesignを触っている気分になった。

まとめ

参考

Mastering TextKit

iOSDC 2018 2日目に参加してきた

概要

iOSDC2日目に参加したので、そのまとめ。
参加したセッションまとめと、感想を記しておく。

セッションまとめと感想

登壇者が話したことと感想とが混じっているので、雰囲気で察してくれることを祈る

詳解Fastfile by ぎぎにゃん

  • 資料
  • fastfileの詳細について話すよ
  • fastlineの活用事例
    • コードレビュー
      • Danger用に自社で作ったスペルチェックツール、いいな
    • サブミット
      • CIでリリースビルドしてサブミット
      • SlackBOTからサブミット
      • 定期的にmasterをビルドしてサブミット
        • 強いな
    • 社内向けビルド
      • エンタープライズライセンスでビルドして配信サービスで社内配布
      • PRごとに配布
      • 社内向け配信サービスは16時から話すよ
    • メトリクス収集
  • ありがちなこと
    • なんでもfastfileに書きがち
  • メンテしやすい最高のfastfileの書き方
    • Fastfile
      • 基本的にはRuby
  • import
    • 複数のfastfileを読み込んで実行できる
  • GitHubでシンタックスハイライト
    • 一行目に #vim: syntax=ruby って書くといいよ
  • 公式のAdvanced Featureを読む
  • いろいろ書きやすいがゆえに肥大化する
  • 最高のFastfileとは
    • 書かない
    • コードを書くところではないので、書くものを減らす
  • コツ
    • 値を書きすぎない
      • 環境変数を利用する
    • 設定とロジックを分離する
      • ~fileを利用する
        • Gymfileなど
    • Actionを分離する
      • テンプレートを作るコマンド bundle exrc fastlane new_action があるので、それを利用して作成するとよい
      • パラメータのバリデーションがしやすい
        • 型チェック
      • テストが書きやすい(RSpec)
  • コードサイン
    • AutomaticはCIでこけやすい。理由はわからない
      • よく聞く話だー
    • matchはGitで管理しているプロファイルをいい感じに取得する…らしい
    • 正しい世界観はXcodeのコンフィグレーションを使うのがよいのではないか
      • Xcode9からAutomaticとManualが同居できるようになった
  • 最高の設定
  • fastlaneあるある
    • 手元での確認がだるい
  • デバッガを使う
    • Rubyのデバッガ
      • pry
    • .envrc
    • envchain
    • direnv

Depth in Depth

  • 資料
  • Depth
    • 深度
  • 深度の用途:背景を飛ばす
    • フリマ系アプリで出品時に背景を飛ばすなどの用途がある
  • 深度の用途:3Dスキャン
  • 深度の用途:その他
    • ZOZOスーツの「30センチ後ろにさがってください」などの検知に使っていそう
  • 深度は発想次第で写真以外にも用途がいろいろある!
  • Disparity(視差)
    • 人間の左右の目で見えるものが違う
    • iPhone7以降の背面カメラで利用
  • DepthはDisparityから計算できる
    • Depthの逆数=正規化されたDisparity
  • Time of Flight
    • iPhoneXの前面カメラ
  • iOSで取得する方法
    • AVDepthData
      • 深度を表すクラス
      • どの方法で取得しても最終的にこれが得られる
      • iOS11以上
      • var depthDataMap: CVPixcelData
    • 用途別にわけると3種類
      • 撮影済の写真
      • カメラからリアルタイムに取得
        • AVCaptureDevice
      • ARKitから取得
        • ARFrameにプロパティがある
  • 方法に優劣はなく、用途に応じたものを使う
  • 背景合成の手法
    • マスク画像を基準に、オリジナル画像と背景画像をブレンドする
    • CIBlendWithMask
  • 顔の深度をしきい値に、深度マップを2値化する
  • PotraitMatte
  • どういうケースで、なにができてなにができないのか把握しづらい

5000行のUITableViewを差分更新する

  • 資料
  • UITableViewで差分更新、パフォーマンスの話
  • UITableViewで差分更新する
    • 特徴
      • 行数がたくさんあっても早い
    • 更新方法
      • 全部更新
        • アニメーションなしだが、簡単に使える
      • 差分更新
  • 差分更新をどう実現するか
    • 差分のIndexPathを正確に指定するだけ
    • diffを使おう
  • diffとpatch applyをしている
  • 差分更新はここがいい
    • きれいでわかりやすいアニメーション
  • 既存アプリ+差分更新
    • 来週からでもいれてみたらいい
      • あかんやつw
    • 実際にやってみた
  • 差分更新いれてみた
    • reloadData()を置き換えていく
    • 遅すぎた。Filterが遅すぎる
    • reloadData()のほうがマシでは?
  • パフォーマンス解析するのにInstruments
    • Timer Profiler
  • Timer Profilerでわかること
    • アプリ実行中のCPU負荷の時系列のグラフ
  • differを使って調査
  • 調査した結果、diffに時間がかなりかかっていた
    • firebaseの指標値内に収めたい
  • diffのあとはpatchのパフォーマンス改善
    • 削除に時間がかかる
      • reloadData()に戻すという方法もある
  • diffの行数だけ計算させて、行数が少なければそのままライブラリ、多ければreloadData()を使うという方法をとった
    • 差分更新と多数行削除の共存
  • banjun/GigDiffer というコンセプト実装ライブラリを作った

Synchronized iPhones!

  • 資料
    • まだない
  • Syncしてやりたいこと
    • iOS端末のリフレッシュレートにあわせる
      • 最も早いリフレッシュレートは60fps
    • CADisplayLinkを使えば、リフレッシュレートにあわせて描画できる
  • iOSデバイスの時刻をあわせる
    • NTP、GPS、NITZ

LT

メモ取る時間がない感じなので、諦めた。
全般的にルーキーという感じがまったくしなくて、とても良かった。

下記のLT資料は、あとで読みたい。
Appleのアニメーションはなぜ美しいか考える

まとめ

デザインやアニメーションについての言及があるセッションがあって、音系のセッションもあって、実り多いカンファレンスだ。

iOSDC 2018 1日目に参加してきた

概要

iOSDC1日目に午前中だけ参加したので、そのまとめ。
参加したセッションまとめと、感想を記しておく。

セッションまとめと感想

登壇者が話したことと感想とが混じっているので、雰囲気で察してくれることを祈る

複数のライブ映像を同期再生するのが大変だったので知見をお伝えします ~~

  • 資料
  • ライブストリーミング系の話は気になる
    • 同期はやったことないけど
  • AVPlayerはしんどいので、できるだけWKWebViewやAVPlayerViewControllerを使おう
    • AudioToolboxで実装するよりはAVPlayerのほうが数段楽なのでは
  • お、やっぱりHLSだ
  • WWDC2017のAdvance in HTTP Live Steamingをみるとだいたい実装できる
  • KVO
    • 音声系のHLSでObjCで実装したなー
  • iOS9のサポートを切る
    • なるほど…
    • iOS10以上じゃないとAPIがないとのこと
  • 設計上のコツ
    • Viewにデータが密結合しやすい
    • 複数の動画が密結合する
    • Managerを作って同期に必要なデータを外に出す
    • わかる、わかるぞ…
  • AVPlayerItem の preferredForwardBufferDuration でバッファ時間の調節ができる

MicroViewControllerで無限にスケールするiOS開発

  • 資料
  • 一番聞きたかったやつ
  • コンポーネントがすべてVCらしい?
  • 層に分割することが目的ではない
  • Micro化することでパフォーマンスがあがる
    • レイアウトに一番時間がかかる
  • StoryboardではなくXIBを使っている
    • IBを使う理由はAutolayoutのエラーを実行前に確認できる手段だから
  • ボタンの種類ごとにVCが存在する
    • まじか…
  • IFを統一した
    • ですよねー
    • じゃないと、現実的に無理だよね
  • かなり強い型プログラミングができる
  • テンプレートでVCの生成を行っている
    • よいぞ
  • サンプルコード

まとめ

フォントと組版の話が聞きたかったけど、用事があるので残念。 明日も楽しみ。

前夜祭の記事

www.macneko.com