Rodhos Soft

備忘録を兼ねた技術的なメモです。Rofhos SoftではiOSアプリ開発を中心としてAndroid, Webサービス等の開発を承っております。まずはご相談下さい。

デバッグ シンボライズ

Xode内にあるsymbolicatecrashを使う。以下を参照した。
www.crunchtimer.jp


まず探す。Xcode8のフォルダ内で

find . -name symbolicatecrash
/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash

面倒なので適当にln -sでシンボリックリンクを作っておく。

次に対応するアプリのdSYMファイルがいる。

Library/Developer/Xcode/DerivedData/hogehoge/Build/Products/Debug-iphoneos

実行してみる

 ./symbolicatecrash hoge.crash hoge.app.dSYM/
Error: "DEVELOPER_DIR" is not defined at ./symbolicatecrash line 69.

シンボリックリンクをはる。

$ export DEVELOPER_DIR=”/Applications/Xcode.app/Contents/Developer/”

再度実行した。

xcrun: error: missing DEVELOPER_DIR path: ”/Applications/Xcode.app/Contents/Developer/”
## Warning: can't find tool named 'otool' in iOS SDK, falling back to searching the Mac OS X SDK
xcrun: error: missing DEVELOPER_DIR path: ”/Applications/Xcode.app/Contents/Developer/”
Error: can't find tool named 'otool' in the macosx SDK or any fallback SDKs at ./symbolicatecrash line 122.

以下のサイトのやり方に従う
stackoverflow.com

sudo /usr/bin/xcode-select -switch /Applications/Xcode.app/Contents/Developer

xcode-selectのヘルプをみてみた。

/usr/bin/xcode-select -h
Usage: xcode-select [options]

Print or change the path to the active developer directory. This directory
controls which tools are used for the Xcode command line tools (for example, 
xcodebuild) as well as the BSD development commands (such as cc and make).

Options:
  -h, --help                  print this help message and exit
  -p, --print-path            print the path of the active developer directory
  -s <path>, --switch <path>  set the path for the active developer directory
  --install                   open a dialog for installation of the command line developer tools
  -v, --version               print the xcode-select version
  -r, --reset                 reset to the default command line tools path


xcode-selectのswitchをやりつつDEVELOPER_DIRのシンボリックリンクをはった結果
symbolicatecrashに成功した。

個々の解析

しかし、なぜかdSYMがうまく読み込めなかったため、方針を変更し以下のサイトに従ってatosをためした。
developer.apple.com

クラッシュレポートの以下をシンボル化したいとする。

0   Hoge                         	0x00000001000ea5d8 0x100020000 + 828888
atos -arch arm64 -o HogeApp.app.dSYM/Contents/Resources/DWARF/Hoge -l 0x100020000 0x00000001000ea5d8

Hogeはbinary image name
0x100020000はload address
0x00000001000ea5d8はシンボル化したいアドレス

これでシンボル化ができた。


参照したサイト
www.crunchtimer.jp
irabbit.seesaa.net
stackoverflow.com

swiftc failed with exit code 1

Command /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc failed with exit code 1

で妙な現象にあった。

    func reload(completion:@escaping (T?, Error?) -> Void) {
        objc_sync_enter(self.loadCompletions)
        loadCompletions.append(completion)
        objc_sync_exit(self.loadCompletions)
        
        self.reload()
    }

とすると発生し、

    func reload(completion:@escaping (T?, Error?) -> Void) {
        objc_sync_enter(self.loadCompletions)
        loadCompletions = loadCompletions + [completion]
        objc_sync_exit(self.loadCompletions)
        
        self.reload()
    }

とすると発生しない。
これに気づくのにだいぶ時間を取られたが、発生理由がわからない。。loadCompletionsはvarで定義してあるのでappendで問題ないはずだが..。

同じ現象にあわれた人の参考になれば幸いです..orz。

swiftc

Swiftをコマンドラインコンパイルする方法

swiftcを使う。

which swiftc
/usr/bin/swiftc

適当にswiftでコードを書いて、

import Foundation
print("hello, world!")

ここではmain.swiftという名前にした。

swiftc main.swift

これで、mainという実行ファイルができるのじ実行するとhello worldできる。

出力を変えたい場合は

swiftc -o hoge main.swift 

複数ファイル

main.swiftは

import Foundation

print("start")

let hello = Hello()
hello.hello()

新しくHello.swiftを

import Foundation

class Hello {
    
    func hello() {
        print("hello")
    }
}

と作る。

コンパイル

swiftc main.swift Hello.swift

でいける。



ヘルプを見る

swiftc -help

OVERVIEW: Swift compiler

USAGE: swiftc [options] <inputs>

MODES:
  -dump-ast        Parse and type-check input file(s) and dump AST(s)
  -dump-parse      Parse input file(s) and dump AST(s)
  -dump-type-refinement-contexts
                   Type-check input file(s) and dump type refinement contexts(s)
  -emit-assembly   Emit assembly file(s) (-S)
  -emit-bc         Emit LLVM BC file(s)
  -emit-executable Emit a linked executable
  -emit-ir         Emit LLVM IR file(s)
  -emit-library    Emit a linked library
  -emit-object     Emit object file(s) (-c)
  -emit-sibgen     Emit serialized AST + raw SIL file(s)
  -emit-sib        Emit serialized AST + canonical SIL file(s)
  -emit-silgen     Emit raw SIL file(s)
  -emit-sil        Emit canonical SIL file(s)
  -parse           Parse input file(s)
  -print-ast       Parse and type-check input file(s) and pretty print AST(s)

OPTIONS:
  -application-extension  Restrict code to those available for App Extensions
  -assert-config <value>  Specify the assert_configuration replacement. Possible values are Debug, Release, Unchecked, DisableReplacement.
  -D <value>              Marks a conditional compilation flag as true
  -embed-bitcode-marker   Embed placeholder LLVM IR data as a marker
  -embed-bitcode          Embed LLVM IR bitcode as data
  -emit-dependencies      Emit basic Make-compatible dependencies files
  -emit-module-path <path>
                          Emit an importable module to <path>
  -emit-module            Emit an importable module
  -emit-objc-header-path <path>
                          Emit an Objective-C header file to <path>
  -emit-objc-header       Emit an Objective-C header file
  -fixit-all              Apply all fixits from diagnostics without any filtering
  -fixit-code             Get compiler fixits as code edits
  -framework <value>      Specifies a framework which should be linked against
  -F <value>              Add directory to framework search path
  -gdwarf-types           Emit full DWARF type info.
  -gline-tables-only      Emit minimal debug info for backtraces only
  -gnone                  Don't emit debug info
  -g                      Emit debug info. This is the preferred setting for debugging with LLDB.
  -help                   Display available options
  -import-underlying-module
                          Implicitly imports the Objective-C half of a module
  -index-store-path <path>
                          Store indexing data to <path>
  -I <value>              Add directory to the import search path
  -j <n>                  Number of commands to execute in parallel
  -L <value>              Add directory to library link search path
  -l<value>               Specifies a library which should be linked against
  -module-cache-path <value>
                          Specifies the Clang module cache path
  -module-link-name <value>
                          Library to link against when using this module
  -module-name <value>    Name of the module to build
  -nostdimport            Don't search the standard library import path for modules
  -num-threads <n>        Enable multi-threading and specify number of threads
  -Onone                  Compile without any optimization
  -Ounchecked             Compile with optimizations and remove runtime safety checks
  -output-file-map <path> A file which specifies the location of outputs
  -O                      Compile with optimizations
  -o <file>               Write output to <file>
  -parse-as-library       Parse the input file(s) as libraries, not scripts
  -parse-sil              Parse the input file as SIL code, not Swift source
  -parseable-output       Emit textual output in a parseable format
  -profile-coverage-mapping
                          Generate coverage data for use with profiled execution counts
  -profile-generate       Generate instrumented code to collect execution counts
  -sanitize-coverage=<type>
                          Specify the type of coverage instrumentation for Sanitizers and additional options separated by commas
  -sanitize=<check>       Turn on runtime checks for erroneous behavior.
  -save-temps             Save intermediate compilation results
  -sdk <sdk>              Compile against <sdk>
  -serialize-diagnostics  Serialize diagnostics in a binary format
  -static-stdlib          Statically link the Swift standard library
  -suppress-warnings      Suppress all warnings
  -target-cpu <value>     Generate code for a particular CPU variant
  -target <value>         Generate code for the given target
  -tools-directory <directory>
                          Look for external executables (ld, clang, binutils) in <directory>
  -use-ld=<value>         Specifies the linker to be used
  -version                Print version information and exit
  -v                      Show commands to run and use verbose output
  -warnings-as-errors     Treat warnings as errors
  -whole-module-optimization
                          Optimize input files together instead of individually
  -Xcc <arg>              Pass <arg> to the C/C++/Objective-C compiler
  -Xlinker <value>        Specifies an option which should be passed to the linker

参考になりそうなサイト
qiita.com
yamaimo.hatenablog.jp

デバッグ lldb

ブレークポイントセット

breakpoint set -n semaphore_wait_trap

LLDB 使い方まとめ - Qiita
dispatch_barrier_sync blocks main thread when re-requesting an image. · Issue #803 · rs/SDWebImage · GitHub

script

Pythonでscript入力
exit()で終了

[LLDB] Pythonで独自コマンドを作ってみる - Qiita
https://lldb.llvm.org/python-reference.html
https://lldb.llvm.org/scripting.html

ヘルプ

help

スレッド全リスト

th list

スレッドの選択

(lldb) th sel 2

frame情報

fr info

frame選択

fr sel 1

frame内ローカル変数

fr variable

バックトレース

bt

bt allで全スレッドバックトレース



iOSエンジニアのための LLDB Plugin 入門 - NANAIRO

連打防止

秒数をカウントしてやる。

    class DoubleTap {
        var actionTime:Date? = nil
        let actionInterval:TimeInterval = 0.3
        
        func check() -> Bool {
            if let actionTime = actionTime {
                if -actionTime.timeIntervalSinceNow < actionInterval {
                    return false
                }
            }
            
            self.actionTime = Date()
            return true
        }
    }
    let doubleTap:DoubleTap = DoubleTap()

事前にチェックしてfalseなら無視する。

テーブルを連携させる

2つのテーブルの連携を考える。

peapleテーブル(personの複数形)

id INT,プライマリキー,AutoIncrement
name Text, Not Null, Unique
password Text, Not Null
comment Text, Null

boardsテーブル

id Int,プライマリキー,AutoIncrement
person_id Not Null
title Text
content Text

person_idは外部キーということになる。

テーブルの結合

3つのJOIN

  1. LEFT JOIN
  2. RIGHT JOIN
  3. INNER JOIN

わかりやすい解説があった。
A Visual Explanation of SQL Joins

このリンクを読んだ後以下を読むと意味がわかる。
qiita.com








PHPフレームワーク CakePHP 3入門

bake

bookモデルを作りそのCRUDをbakeで作る。

データベースでbooksテーブル作成

id 整数、プライマリー、自動インクリメント
title テキスト
author テキスト
price 整数

bake

$ ./bin/cake bake all books

しかし失敗する

Exception: SQLSTATE[HY000] [2002] Connection refused in [*****/hogemysql/vendor/cakephp/cakephp/src/Database/Driver/PDODriverTrait.php, line 47]

Config/app.php で 以下のようにhostとportを設定したところ通った。

'Datasources' => [
        'default' => [
// 略
            'host' => '127.0.0.1',
            'port' => '8889',
        // 略
        ],


これだけで追加、編集等の画面毎作れる。

TableのvalidationDefault

bakeしたtableにはバリデーションが設定されている。

    public function validationDefault(Validator $validator)
    {
        $validator
            ->integer('id')
            ->allowEmpty('id', 'create');

        $validator
            ->requirePresence('title', 'create')
            ->notEmpty('title');

        $validator
            ->requirePresence('author', 'create')
            ->notEmpty('author');

        $validator
            ->integer('price')
            ->requirePresence('price', 'create')
            ->notEmpty('price');

        return $validator;
    }

データベース操作

レコード追加

テンプレー側にフォームを用意

<?= $this->Form->Create($entity, ['url'=>['action'=>'addRecord']]) ?>
<fieldset>
<?= $this->Form->text("name") ?>
<?= $this->Form->text("title") ?>
<?= $this->Form->textarea("content") ?>
</fieldset>
<?= $this->Form->button("送信") ?>
<?= $this->Form->end() ?>

コントローラにaddRecord追加

<?php

namespace App\Controller;

class BoardsController extends AppController {
  public function index() {
    $data = $this->Boards->find('all');
    $this->set('data', $data);
    $this->set('entity', $this->Boards->newEntity());/* 空のものをセット*/
  }

  public function addRecord() {
    if ($this->request->is('post')) {
      $board = $this->Boards->newEntity($this->request->data);
      $this->Boards->save($board);
    }

    return $this->redirect(['action' => 'index']);
  }
}

?>

request_dataの中身確認

中身をprintしてみる

  public function addRecord() {
    if ($this->request->is('post')) {
      $board = $this->Boards->newEntity($this->request->data);
      $this->Boards->save($board);
    }

    $this->autoRender = false;
    echo "<pre>";
    print_r($this->request->data);
    echo "</pre>";

//    return $this->redirect(['action' => 'index']);
  }

結果、
このような連想配列が入っていることがわかった。

Array
(
    [name] => hoge
    [title] => hello
    [content] => I have a pen.
)

レコードの検索

特定レコード表示をfindを使って実装する。index.ctpに以下を追加

<h2>検索</h2>
<?= $this->Form->Create($entity, ['url'=>['action'=>'index']]) ?>
<fieldset>
<?= $this->Form->text("id") ?>
</fieldset>
<?= $this->Form->button("送信") ?>
<?= $this->Form->end() ?>

コントローラのindexを修正

  public function index() {

    $this->set('entity', $this->Boards->newEntity());

    if ($this->request->is('post')) {
      $data = $this->Boards->find('all',
        ['conditions' => ['id' => $this->request->data['id']]]
      );
    } else {
      $data = $this->Boards->find('all');
    }
    $this->set('data', $data);
  }

find

第1引数

all 全レコード
list レコードのリスト(表示用のフィールドだけ入っている)
threaded スレッド状レコード(ネストされたエンティティを扱う際に必要)

第2引数

conditions 条件設定
fields 取得するフィールド名を配列として用意
recursive 再帰的に取得する深度
order 取得順
limit 上限
offset 取得開始位置
page 取得ページ数

like 検索

テンプレートをidからtitleに書き換え

<h2>検索</h2>
<?= $this->Form->Create($entity, ['url'=>['action'=>'index']]) ?>
<fieldset>
<?= $this->Form->text("name") ?>
</fieldset>
<?= $this->Form->button("送信") ?>
<?= $this->Form->end() ?>

コントローラもlikeを使ったものにかきかえ

  public function index() {

    $this->set('entity', $this->Boards->newEntity());

    if ($this->request->is('post')) {
      $data = $this->Boards->find('all',
        ['conditions' =>
          ['name like' => "%{$this->request->data['name']}%"]
        ]
      );
    } else {
      $data = $this->Boards->find('all');
    }
    $this->set('data', $data);
  }

これでその文字を含むnameの検索になった。

findで取得したQueryを調べる。

コントローラにindexを生やして出力させてみた。

public function findtest() {
    $query = $this->Boards->find('all');

    $this->autoRender = false;
    echo "<div>";
    echo "数";
    echo "<pre>";
    print_r($query->count());
    echo "</pre>";
    echo "</div>";

    echo "<div>";
    echo "first";
    echo "<pre>";
    print_r($query->first()->toArray());
    echo "</pre>";
    echo "</div>";

    echo "<div>";
    echo "last";
    echo "<pre>";
    print_r($query->last()->toArray());
    echo "</pre>";
    echo "</div>";

    echo "<div>";
    echo "max_id";
    echo "<pre>";
    print_r($query->max('id'));
    echo "</pre>";
    echo "</div>";

    echo "<div>";
    echo "min_id";
    echo "<pre>";
    print_r($query->min('id'));
    echo "</pre>";
    echo "</div>";


  }

結果は

数
4
first
Array
(
    [id] => 1
    [name] => poi
    [title] => asdasd
    [content] => fawefsfawefaewf
)
last
Array
(
    [id] => 1
    [name] => poi
    [title] => asdasd
    [content] => fawefsfawefaewf
)
max_id
Cake\ORM\Entity Object
(
    [id] => 1
    [name] => poi
    [title] => asdasd
    [content] => fawefsfawefaewf
    [[new]] => 
    [[accessible]] => Array
        (
            [*] => 1
        )

    [[dirty]] => Array
        (
        )

    [[original]] => Array
        (
        )

    [[virtual]] => Array
        (
        )

    [[errors]] => Array
        (
        )

    [[invalid]] => Array
        (
        )

    [[repository]] => Boards
)
min_id
Cake\ORM\Entity Object
(
    [id] => 1
    [name] => poi
    [title] => asdasd
    [content] => fawefsfawefaewf
    [[new]] => 
    [[accessible]] => Array
        (
            [*] => 1
        )

    [[dirty]] => Array
        (
        )

    [[original]] => Array
        (
        )

    [[virtual]] => Array
        (
        )

    [[errors]] => Array
        (
        )

    [[invalid]] => Array
        (
        )

    [[repository]] => Boards
)

firstとlastがおなじになっている。
これは$data->$first とやったことでqueryの内容が変わってしまったことを意味する。

そうならないようにすると(取り直した)

  public function findtest() {
    $query = $this->Boards->find('all');
    $count = $query->count();
    $max_id = $query->max('id');
    $min_id = $query->min('id');

    $first = $this->Boards->find('all')->first();
    $last = $this->Boards->find('all')->last();

    $this->autoRender = false;
    echo "<div>";
    echo "数";
    echo "<pre>";
    print_r($count);
    echo "</pre>";
    echo "</div>";

    echo "<div>";
    echo "first";
    echo "<pre>";
    print_r($first->toArray());
    echo "</pre>";
    echo "</div>";

    echo "<div>";
    echo "last";
    echo "<pre>";
    print_r($last->toArray());
    echo "</pre>";
    echo "</div>";

    echo "<div>";
    echo "max_id";
    echo "<pre>";
    print_r($max_id);
    echo "</pre>";
    echo "</div>";

    echo "<div>";
    echo "min_id";
    echo "<pre>";
    print_r($min_id);
    echo "</pre>";
    echo "</div>";


  }

確かに正常に検索結果がでている。

数
4
first
Array
(
    [id] => 1
    [name] => poi
    [title] => asdasd
    [content] => fawefsfawefaewf
)
last
Array
(
    [id] => 4
    [name] => hoge
    [title] => hello
    [content] => I have a pen.
)
max_id
Cake\ORM\Entity Object
(
    [id] => 4
    [name] => hoge
    [title] => hello
    [content] => I have a pen.
    [[new]] => 
    [[accessible]] => Array
        (
            [*] => 1
        )

    [[dirty]] => Array
        (
        )

    [[original]] => Array
        (
        )

    [[virtual]] => Array
        (
        )

    [[errors]] => Array
        (
        )

    [[invalid]] => Array
        (
        )

    [[repository]] => Boards
)
min_id
Cake\ORM\Entity Object
(
    [id] => 1
    [name] => poi
    [title] => asdasd
    [content] => fawefsfawefaewf
    [[new]] => 
    [[accessible]] => Array
        (
            [*] => 1
        )

    [[dirty]] => Array
        (
        )

    [[original]] => Array
        (
        )

    [[virtual]] => Array
        (
        )

    [[errors]] => Array
        (
        )

    [[invalid]] => Array
        (
        )

    [[repository]] => Boards
)

昇順、降順

orderを使う。

  public function findtest() {
    $query = $this->Boards->find('all');
    $query->order(['name' => 'ASC', 'id' => 'DESC']);


    $this->autoRender = false;
    echo "<div>";
    echo "<pre>";
    print_r($query->toArray());
    echo "</pre>";
    echo "</div>";

  }

動的FInderで検索 findBy___()

以下のようにキャメル記法でフィールド名をByの後に書く。

  public function findtest() {
    $query = $this->Boards->findById('1');

    $this->autoRender = false;
    echo "<div>";
    echo "<pre>";
    print_r($query->toArray());
    echo "</pre>";
    echo "</div>";

  }

2つの条件をorで結びたい場合

    $query = $this->Boards->findByIdOrName('1',"poi");

andも同様。

削除

<h2>削除</h2>
<?= $this->Form->Create($entity, ['url'=>['action'=>'deleteRecord']]) ?>
<fieldset>
<?= $this->Form->text("id") ?>
</fieldset>
<?= $this->Form->button("送信") ?>
<?= $this->Form->end() ?>


コントローラに

use \Exception;
use Cake\Log\Log;

を追加しつつ、以下を追加

  public function deleteRecord() {
    if ($this->request->is('post')) {
      try {
        $entity = $this->Boards->get($this->request->data['id']);
        $this->Boards->delete($entity);
      } catch (Exception $e) {
        Log::write('debug', $e->getMessage());
      }
    }
    $this->redirect(['action' => 'index']);
  }

IDがプライマリーキーなのでエンティティがgetで得られる。
Logはレベルを指定して出力できる。

debug デバッグ
info 情報
notice 注意
warning 警告
error 例外
critical 危険
alert 直ちに対処すべき
emergency システム停止級

条件の範囲を消したい時、例えばnameがhogeのものすべてを消す場合、

$this->Boards->deleteAll(['name' => 'hoge']);

レコードの更新

saveで良い。

index側

<h2>編集</h2>
<?=$this->Form->create($entity,
['url'=>['action'=>'editRecord']]) ?>
<fieldset>
  <p><?= 'ID =' . $entity->id ?></p>
  <?=$this->Form->hidden("id") ?>
  <?=$this->Form->text("name") ?>
  <?=$this->Form->text("title") ?>
  <?=$this->Form->text("content") ?>
</fieldset>
<?=$this->Form->button("送信") ?>
<?=$this->Form->end() ?>

コントローラ側

  public function index($id = null) {

    $this->set('entity', $this->Boards->newEntity());

    if ($id != null) {
      try {
        $entity = $this->Boards->get($id);
        $this->set('entity', $entity);
      } catch (Exception $e){
        Log::write('debug', $e->getMessage());
      }
    }

    $data = $this->Boards->find('all')->order(['id'=>'DESC']);
    $this->set('data', $data->toArray());
  }

  public function editRecord() {

// putに注意
    if ($this->request->is('put')) {
      try {
        $entity = $this->Boards->get($this->request->data['id']);
        $this->Boards->patchEntity($entity, $this->request->data);
        $this->Boards->save($entity);
      } catch (Exception $e) {
        Log::write('debug', $e->getMessage());
      }
    }
    $this->redirect(['action' => 'index']);
  }

これでboards/index/1のようにアクセスして編集できる。



PHPフレームワーク CakePHP 3入門

使いかた

http://pubman.mpdl.mpg.de/pubman/item/escidoc:150722:1/component/escidoc:150721/cadabra.pdf


A brief introduction to Cadabra: a tool for tensor computations in General Relativity
https://arxiv.org/pdf/0903.2085.pdf

https://suppiya.files.wordpress.com/2008/05/comprund_41_016.pdf

http://cds.cern.ch/record/1013176/files/0701238.pdf

macにinstall

github.com

に従ってmakeしようとしたが"cmake .."で失敗中

500エラー

PHPでエラーがみたい

php.iniファイルで

error_reporting  =  E_ALL
display_errors On
display_startup_errors = On

公開用サーバではlog_errorsでログでみるべき。

internal error 500

新しくプロジェクトを作ったところそのようなエラーがでた。
ログを確認したところ

 PHP Fatal error:  require(): Failed opening required '/Applications/MAMP/htdocs/hogemysql/vendor/autoload.php' (include_path='.:/Applications/MAMP/bin/php/php7.1.1/lib/php') in /Applications/MAMP/htdocs/hogemysql/webroot/index.php on line 27

PHP Warning:  require(/Applications/MAMP/htdocs/hogemysql/vendor/autoload.php): failed to open stream: No such file or directory in /Applications/MAMP/htdocs/hogemysql/webroot/index.php on line 27

つまりautoload.phpがないといわれている。

同様の問題と思わしきページ
chaika.hatenablog.com

たしかにログをみてみると

$ php composer.phar create-project --prefer-dist cakephp/app hogemysql
Installing cakephp/app (3.4.2)
  - Installing cakephp/app (3.4.2): Downloading (100%)         
Created project in hogemysql
Loading composer repositories with package information
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - cakephp/cakephp 3.4.7 requires ext-intl * -> the requested PHP extension intl is missing from your system.
    - cakephp/cakephp 3.4.6 requires ext-intl * -> the requested PHP extension intl is missing from your system.
    - cakephp/cakephp 3.4.5 requires ext-intl * -> the requested PHP extension intl is missing from your system.
    - cakephp/cakephp 3.4.4 requires ext-intl * -> the requested PHP extension intl is missing from your system.
    - cakephp/cakephp 3.4.3 requires ext-intl * -> the requested PHP extension intl is missing from your system.
    - cakephp/cakephp 3.4.2 requires lib-icu >=4.8 -> the requested linked library icu has the wrong version installed or is missing from your system, make sure to have the extension providing it.
    - cakephp/cakephp 3.4.1 requires lib-icu >=4.8 -> the requested linked library icu has the wrong version installed or is missing from your system, make sure to have the extension providing it.
    - cakephp/cakephp 3.4.0 requires lib-icu >=4.8 -> the requested linked library icu has the wrong version installed or is missing from your system, make sure to have the extension providing it.
    - Installation request for cakephp/cakephp 3.4.* -> satisfiable by cakephp/cakephp[3.4.0, 3.4.1, 3.4.2, 3.4.3, 3.4.4, 3.4.5, 3.4.6, 3.4.7].

とintlがないと言われている。
qiita.com

の手順でやってみた。

icu4cインストール(Unicode 関連の処理を行うためのオープンソースのライブラリ)

$ brew install icu4c

autoconfインストール(https://ja.wikipedia.org/wiki/Autotools#autoconf)
が、うまくいかない。

Error: No available formula with the name "icu4cautoconf" 
==> Searching for similarly named formulae...
Error: No similarly named formulae found.
==> Searching taps...
Error: No formulae found in taps.
==> You haven't updated Homebrew in a while.

brew updateしようとしたが

Error: /usr/local must be writable!


qiita.com

とありあえず

brew doctor

してみた。
それにしたがい

sudo chown -R $(whoami) /usr/local

をする。

brew update

が実行できたが

Error: update-report should not be called directly!


もう一度

brew install autoconf
$ sudo pecl update-channels
$ sudo pecl install intl 
sudo: pecl: command not found

遠回りしている気がしたので

brew search intl
intltool
homebrew/php/php53-intl    homebrew/php/php55-intl    homebrew/php/php71-intl
homebrew/php/php54-intl    homebrew/php/php56-intl    homebrew/php/php70-intl
brew install homebrew/php/php71-intl

webアプリのフォルダで

composer install

これでアクセスしたところ表示が500から

Could not load configuration file: /Applications/MAMP/htdocs/hogemysql/config/app.php

に変わった。
もう一度

composer install

したところ

$ composer install
Loading composer repositories with package information
Installing dependencies (including require-dev) from lock file
Nothing to install or update
Generating autoload files
> Cake\Composer\Installer\PluginInstaller::postAutoloadDump
> App\Console\Installer::postInstall
Created `config/app.php` file
Set Folder Permissions ? (Default to Y) [Y,n]? Y
Permissions set on /Applications/MAMP/htdocs/hogemysql/tmp/cache
Permissions set on /Applications/MAMP/htdocs/hogemysql/tmp/cache/models
Permissions set on /Applications/MAMP/htdocs/hogemysql/tmp/cache/persistent
Permissions set on /Applications/MAMP/htdocs/hogemysql/tmp/cache/views
Permissions set on /Applications/MAMP/htdocs/hogemysql/tmp/sessions
Permissions set on /Applications/MAMP/htdocs/hogemysql/tmp/tests
Permissions set on /Applications/MAMP/htdocs/hogemysql/tmp
Permissions set on /Applications/MAMP/htdocs/hogemysql/logs
Updated Security.salt value in config/app.php

となり、無事アクセスが成功した。


whoamiとは

whoami - Wikipedia

MySQL

phpMyAdminがつかえるとして以下話をする。

MySQLにパスワードを設定している場合は
phpMyAdmin/config.inc.php

$cfg['Servers'][$i]['user']          = '*****'; 
$cfg['Servers'][$i]['password']      = '****';

を設定する。

phpMyAdminでデータベース作成

mydata 照合順序 utf8_nicode_ci

テーブル作成

boards フィールド数4

フィールド設定

id INT PRIMARY A_I
name VARCHAR(255) Null
title VARCHAR
content TEXT
CREATE TABLE `mydata`.`boards` ( `id` INT NOT NULL AUTO_INCREMENT , `name` VARCHAR(255) NULL , `title` VARCHAR(255) NOT NULL , `content` TEXT NOT NULL , PRIMARY KEY (`id`)) ENGINE = InnoDB;

ダミーレコード入力

挿入で適当に数件入れる。

INSERT INTO `boards` (`id`, `name`, `title`, `content`) VALUES (NULL, 'poi', 'asdasd', 'fawefsfawefaewf');
INSERT INTO `boards` (`id`, `name`, `title`, `content`) VALUES (NULL, 'piopoi', 'asdasd', 'ddddddddddwwwwwssssxxxx');

CakePHPのデータベースファイルをMySQLに変更する

Config/app.php

    'Datasources' => [
        'default' => [
            'className' => 'Cake\Database\Connection',
            'driver' => 'Cake\Database\Driver\Mysql',
            'persistent' => false,
            'host' => 'localhost',
            /**
             * CakePHP will use the default DB port based on the driver selected
             * MySQL on MAMP uses port 8889, MAMP users will want to uncomment
             * the following line and set the port accordingly
             */
            //'port' => 'non_standard_port_number',
            'username' => '****',
            'password' => '****',
            'database' => 'mydata',
            'encoding' => 'utf8',
            'timezone' => 'UTC',
            'flags' => [],
            'cacheMetadata' => true,
            'log' => false,
            'quoteIdentifiers' => false,
            'url' => env('DATABASE_URL', null),
        ],

表示用意

例によってコントローラ用意

<?php

namespace App\Controller;

class BoardsController extends AppController {
  public function index() {
    $data = $this->Boards->find('all');
    $this->set('data', $data);
  }
}

?>

エンティティとテーブル用意

<?php
  namespace App\Mode\Entity;

  use Cake\ORM\Entity;

  class Board extends Entity
  {
    protected $_accessible = [
      '*' => true,
      'id' => false
    ];
  }
?>
<?php
  namespace App\Model\Table;

  use Cake\ORM\Table;

  class BoardsTable extends Table {
    
  }

  ?>

ビューの作成
Template/Boards/index.ctp

<h1>DataBase</h1>

<table>
<tr>
  <th>ID</th>
  <th>Title</th>
  <th>Content</th>
</tr>

<?php
$arr = $data->toArray();
for ($i = 0;$i < count($arr);$i++) {
  echo $this->Html->tableCells(
      $arr[$i]->toArray(),
      ['style' => 'background-color:#f0f0f0'],
      ['style' => 'font-weight:bold'],
      true);
}
?>

</table>

おさらい

いままでのおさらい。

プロジェクト作成

mkdir hoge
php composer.phar create-project --prefer-dist cakephp/app hoge

Hello World

<?php
  namespace App\Controller;

  class HelloController extends AppController {
    public $autoRender = false;
    public function index() {
      echo "hello world!!";
    }
  }
?>

hello/other

<?php
  namespace App\Controller;

  class HelloController extends AppController {
    public $autoRender = false;
    public function index() {
      echo "hello, world!!";
    }
    public function other() {
      echo "hello, other world!!";
    }
  }
?>

フォワードとリダイレクション

<?php
  namespace App\Controller;

  class HelloController extends AppController {
    public $name = "Hello";
    public $autoRender = false;
    public function index() {
      echo "hello, world!!";
    }
    public function other() {
      echo "hello, other world!!";
    }

    // アクションを指定
    public function forw() {
      $this->setAction(other);
    }
    
  // ブラウザにベージ移動を依頼する
    public function red() {
      $this->redirect("/hello/other");
    }

  }
?>

テンプレート

作る場所の例
src/Template/Hello/index.ctp

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta http-equiv="content-type" content="text/html;
  charset=UTF-8">
  <title>Hello Page</title>
</head>

<body>
    <h1>midashi</h1>
    <p> hello hello </p>
</body>
</html>

コントローラ側でautoRenderをtrueにしてテンプレートを読み込む。

<?php
  namespace App\Controller;

  class HelloController extends AppController {
    public $name = "Hello";
    public $autoRender = true;
    public function index() {
      $this->viewBuilder()->autoLayout(false);
    }
  }
?>

autoLayoutをtrueにする場合、テンプレートは

   <h1>midashi</h1>
    <p> hello hello </p>

だけでよく、デフォルトのsrc/Template/Layout/default.ctp
が適用される。

レイアウト

スタイルシートを用意する。
webroot/css/cake.hello.css

body {
  background: #eee;
  color: #999;
  margin: 10px 8px
}

#header {
  font-size: 18pt;
  font-weight: bold;
  margin: 10px;
}

#content {
  background: #fff;
  color: #999;
  padding: 10px 25px 30px 25px;
  font-size: 14pt;
}

#footer {
  text-align: right;
  font-size: 12pt;
  margin: 10pt;
}

h1 {
  color: #aaa;
  font-size: 24pt;
  margin: 20pt 0pt 50pt 0pt;
}

cssを利用する側のテンプレートを書く
src/Template/Layout/hello.ctp

<!DOCTYPE html>
<html>
<head>
    <?= $this->Html->charset() ?>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>
        <?= $this->fetch('title') ?>
    </title>
    <?= $this->Html->meta('icon') ?>

    <?= $this->Html->css('cake.hello.css') ?>

    <?= $this->fetch('meta') ?>
    <?= $this->fetch('css') ?>
    <?= $this->fetch('script') ?>
</head>

<!-- fetchでコントローラの変数を取ってきている。 -->

<body>

<div id="container">
  <div id="header">header</div>

  <div id="content">
      <?=$this->fetch('content') ?>
  </div>

  <div id="footer">footer</div>

</body>
</html>

jsも使いたい場合、ファイルをwebroot/js/cake.hello/jsに用意し、

   <?= $this->Html->script('cake.hello.js') ?>

を追加する。

最後に、コントローラでレイアウトを指定する。

<?php
  namespace App\Controller;

  class HelloController extends AppController {
    public $name = "Hello";
    public $autoRender = true;
    public function index() {
      $this->ViewBuilder()->layout('Hello');
    }
  }
?>

エレメント

レイアウトにはめ込んで使える。Templete/Elementフォルダにいれておき、

 <?= $this->element('hoge') ?>

で読み込める。

値を渡す場合

 <?= $this->element('hoge', ['x'=>10,'y'=>5]) ?>

値の受け渡し

コントローラからテンプレートへ

      $this->set('poi',10);

テンプレート側は

  <p>
      <?= $poi ?>
    </p>

AppController->requestの連想配列

params 送信された値すべて
data POSTされた際の内容
query クエリー
url 送信アドレス
base ベースのディレクト
webroot webrootディレクト
here 現在のアドレス

フォームヘルパー

テンプレート側

  <p> ヘルパーを使ったフォームの送信</p>

    <p>
      <?= $result; ?>
    </p>

    <!-- FormHelperクラスを使ってformタグ生成 第1引数は値を保管するモデル名だが指定していないのでnull-->
    <?= $this->Form->create(null,
    ['type' => 'post',
    'url' => ['controller' => 'Hello', 'action' => 'index']]) ?>

    <!-- inputタグ生成 フィールド名を指定、HelloFormのところはモデル名を指定していればそれを入れる -->
    <?= $this->Form->text("HelloForm.text1") ?>

    <!-- 送信ボタンタグ -->
    <?= $this->Form->submit("送信") ?>

    <!-- タグの終了 -->
    <?= $this->Form->end(); ?>

コントローラ側

<?php
  namespace App\Controller;

  class HelloController extends AppController {

// 略

    public function index() {

// 略

      $result = "";

      if ($this->request->isPost()) {

        $result = "<pre>送信情報<br/>";

        foreach ($this->request->data['HelloForm'] as $key => $value) {
          $result .= $key . ' => ' . $value;
        }

        $result .= "</pre>";

      } else {
        $result = "送信してください";
      }
      $this->set("result", $result);
    }

// 略


  }
?>

モデル = テーブル + エンティティ

例としてBoardモデルを考える

モデル Board キャメル記法
データベーステーブル boards 小文字複数形 アンダースコア記法(クラスでないので)
エンティティ Board Board.php キャメル記法(クラスなので)
コントローラ BoardsController BoardController.php キャメル記法(クラスなので)
ビュー(テンプレート) Template/Boards index.ctp等を配置

SQLiteの用意

SQLite3で自前で作る。ダミーレコードもいれておく

$ sqlite3 mydata
sqlite> create table 'boards' ( 'id' integer primary key autoincrement, 'name' text not null, 'title' text, 'content' text);
sqlite> insert into 'boards' values (1,'name','test','test!');
sqlite> insert into 'boards' values (2,'name2','test2','test?');

.tables, select * from 'boards'等で確認

データベース設定

Config/app.php のDatasourcesをいじる

<?-
// 略
    'Datasources' => [
        'default' => [
            'className' => 'Cake\Database\Connection',
            'driver' => 'Cake\Database\Driver\Mysql', // ここをSqliteに
            'persistent' => false,
            'host' => 'localhost', // 消す
            //'port' => 'non_standard_port_number',
            'username' => 'my_app', // 消す
            'password' => 'secret', // 消す
            'database' => 'my_app', // ROOT . DS . 'db' . DS . 'mydata' とする(使うファイル名を、拡張子あるならそれをつけて)。DSはパス区切りを表す。
            'encoding' => 'utf8',
            'timezone' => 'UTC',
            'flags' => [],
            'cacheMetadata' => true,
            'log' => false,

            'quoteIdentifiers' => false,

            //'init' => ['SET GLOBAL innodb_stats_on_metadata = 0'],

            'url' => env('DATABASE_URL', null),
        ],

// 略

    ],
->

これでアプリ名にアクセス(例  ***/hoge)でwelcomeページをみて、下の方のdatabaseの項目が「CakePHP is able to connect to the database.」にチェックがついていることを確認する。

エンティティクラスの作成

src/Model/EntityにBoard.phpファイルを作成

<?php
namespace App\Model\Entity;

use Cake\ORM\Entity;

class Board extends Entity {
  // 値の一括代入用の設定 id以外のすべては一括代入可能
  protected $_accessible = [
    '*' => true,
    'id' => false
  ];
}

?>

テーブルクラスのファイルを作成

src/Model/TableにBoardsTable.phpファイルを作成

<?php 
  namespace App\Model\Table;

  use Cake\ORM\Table;

  class BoardsTable extends Table {
    
  }

 ?>

コントローラの作成

<?php
namespace App\Controller;

class BoardsController extends AppController {
  public function index() {
    $data = $this->Boards->find('all'); // $dataはQueryクラス
    $this->set('data', $data);
  }
}
?>

ビューの作成

src/Template内にBoardsフォルダを作成、index.ctpファイルを作る。

<h1> データ </h1>
<table>
  <thead>
    <tr>
      <th>ID</th>
      <th>NAME</th>
      <th>TITLE</th>
      <th>CONTENT</th>
    </tr>
  </thead>
  <tbody>
    <?php foreach ($data as $obj): ?> <!-- $objはBoardエンティティクラス -->
      <tr>
        <td> <?= $obj->id ?> </td>
        <td> <?= h($obj->name) ?></td>
        <td> <?= h($obj->title) ?></td>
        <td> <?= h($obj->content) ?></td>
      </tr>
    <?php endforeach; ?>
  </tbody>
</table>

HTMLヘルパーでテーブルを作る

<table>
  <thead>
    <tr>
      <th>ID</th>
      <th>NAME</th>
      <th>TITLE</th>
      <th>CONTENT</th>
    </tr>
  </thead>
  <?php
  $arr = $data->toArray();// 配列に取り出す
  for ($i = 0 ; $i < count($arr); $i++) {
    echo $this->Html->tableCells(
      $arr[$i]->toArray(),
      ['style' => 'background-color:#f0f0f0'],
      ['style' => 'font-weight:bold'],
      true);
  }
  ?>
</table>

技術英語

WWDCをみつつ

Existentials 存在に関する(実存的な)
Compilation コンパイル、編集物
Inference 推論
thunks サンク 遅延評価を受ける関数に受け渡す引数 
ストリーム (プログラミング) - Wikipedia

inception 開始、発端
Interruptible 中断可能、割り込み可能
subvert 倒す、破壊する、覆す
elapse 経過する、過ぎ去る

WWDC2017

iOS11の忘備録

まずQiitaを一読して後追いする。WWDC2017を個別にみていきたい。恐らくリンク先の堤さん等のまとめ(API Diffsから見る iOS 11 の新機能 #WWDC17 - Over&Out その後)
を読むほうが早い..。

以下作成中

レビュー催促ポップアップの規制

Apple、アプリ上でレビューを催促するポップアップを今後は規制
iphone-mania.jp

iOS10.3からSKStoreReviewController
これに一本化される。

MusicKit

iTuneの曲の再生、プレイリスト取得等
MusicKit - Apple Developer
qiita.com

DeviceCheck

qiita.com

アプリのデバイスごとの識別情報。アプリを消しても一緒に消えない個別情報。

MapKit機能追加

MKMarkerAnnotationViewが追加されたのが大きいような気がする。表示の優先順位とかもつけられるようになった。
qiita.com

WKWebView機能追加

cookie管理、カスタムリソース(端末内の画像とかをhtmlに入れられる)、コンテンツブロックが追加された。
qiita.com

Core ML

機械学習系、学習済みのものを使ったりできる。appleが幾つか学習済みデータのサンプルを以下で提供しているのでそれを使ってみるのが良いかも。
少し調べる必要がある。
d.hatena.ne.jp
Machine Learning - Apple Developer
Core ML | Apple Developer Documentation

Depth API

デュアルレンズを使った奥行き判定。AVCaptureDepthDataOutput。
d.hatena.ne.jp
AVCaptureDepthDataOutput - AVFoundation | Apple Developer Documentation

SiriKit機能追加

各種インテントが増えてる。公演のPDF参照。
INTransferMoneyIntent, INSearchForAccountsIntent, INCreateTaskListIntent, INAddTasksIntent, INSetTaskAttributeIntent, INSearchForNotebookItemsIntent,
INGetVisualCodeIntent,
developer.apple.com
SiriKit - Apple Developer
https://devstreaming-cdn.apple.com/videos/wwdc/2017/214bugobsy7xw94v/214/214_whats_new_in_sirikit.pdf

ReplayKit機能追加

RPScreenRecorderというデバイス画面の動画を取れるクラス(AVPlayerからはとれない。)にstartCaptureが追加された。
d.hatena.ne.jp
RPScreenRecorder - ReplayKit | Apple Developer Documentation

SceneKit機能追加

scncameracontroller 情報がない。
SCNCameraController - SceneKit | Apple Developer Documentation

ちなみにSCNCameraとは
SCNCamera - SceneKit | Apple Developer Documentation

ARKit

ARSCNViewやARSKViewは ARSessionを含む。Sessionを動かすにはconfigがいる。ARSessionConfiguration, ARWorldTrackingSessionConfiguration。
ARSession - ARKit | Apple Developer Documentation

WWDC2017ARKIT
developer.apple.com

ARKitはAVFoudationとCoreMotionを使う。ARSessionConfigを設定してARSessionをRunする。ARSessionはAVCaptureSessionとCMMotionManagerを使う。
現在のフレームがARFrame。
特定の位置等をARAnchorで付けたりできる。ARCameraにTracking stateなどの状態が入る(ARSessionから状態通知)。

シーン(場面)の理解としてどこが平面化の理解というのができる。configuration.planeDetection とかで指定しておく。hitTestが frame.hitTestでできる。

Renderingについては

SceneKit のARSCNView
SpriteKitのARSKView
メタルでCustom Renderingする
等がある。


dev.classmethod.jp


SceneKitはiOS8から使える簡易3D描画フレームワーク
qiita.com



サンプルコード
github.com
github.com


アニメーション

developer.apple.com

iOS10から導入されたUIViewPropertyAnimatorに
iOS11で
scrubsLinearly:、pausesOnCompletion:が加わる。

CALayerに.maskedCorners:CACornerMaskが加わる。

Foundation

developer.apple.com



キーパスが簡単に

 let age = ben[keyPath: \Kid.age]
 ben[keyPath: \Kid.nickname] = "Ben"

KVOも

let observation = mia.observe(\.age) {
}
Codableについて