xcode10 & ios12で、layoutSubviews内での[self subviews]が取れなくなった

xcode9 & ios12では問題なく、xcode10 & ios11でも問題なかった。

ただ、xcode10 & ios12の場合、layoutSubviewsで、[self subviews]で何も取れなくなってしまっている。

 

自分の作っていたアプリでは、layoutSubviewsで色々viewをいじっていて、ios12環境だけ何故かそれらが適用されず、色々と調査をした結果、この問題に気づいた。

 

タイミングを1つ遅らせれば良いのではと思い、layoutSubviewsで行うようにした所、問題なく[self subviews]でviewが返ってきた。

 

わかってしまえば非常に単純だが、この問題の調査に数日かけてしまった…。

さくらインターネットの.htaccessでのフォルダ転送、動作しない…

.htaccessによるアクセス制御 – さくらのサポート情報

のURL書き換えリダイレクトを行いたい を見てやったのだが、どうも自分のさくらサーバでは効かず…。

 

今回、自分がやろうとしたのは…

http://xxxx.sakura.ne.jp/image1/xxx.jpg

みたいな感じで来たアクセスを、

http://xxxx.sakura.ne.jp/image2/xxx.jpg

にそのまま飛ばしたい。

 

色々試した結果、なんだか腑に落ちない部分もかなりあるが、

 

RewriteEngine on
RewriteBase /
RewriteRule (.*) "http://xxxx.sakura.ne.jp/images2/$1" [R=301,L]

 

という内容で.htaccessファイルをimage1フォルダに置いた所、動作した。

vscode phpでドルマーク付きの変数をダブルクリックで選択させたい

Visual Studio Code User and Workspace Settings

にある、settings.jsonに、

Make Visual Studio Code to correctly select PHP variables on double-click | Igor Kromin

の1文を加えるだけでokだった。

Flash as3からhaxe+openfl化で直面したエラー群

過去にflash(as3)で作成したそこそこ巨大なプロジェクト(子供向けの教材)をhtml5に移植する仕事を請け負ったが、移植には、haxe+openFLを選択した。

あまり世の中に情報がなかったので、その移植の中で直面した問題を、どう解決したのかを残していきます。

 

 

・以下、ターミナルから、lime test html5 で実行した時のもの。
(openfl test html5 でも同じっぽい)


※また、-debug を付けて実行すると、エラーが起きた時に、どこの行で起きているかまで出してくれるので、基本的に開発中は付けた方がいいと思う。

f:id:suzuki_kuni:20190105001830p:plain

上記は付けた時の状態。付けないと、上記がjsにコンバートされた後の状態での場所になって、全くよくわからないため。

また、その-debugをつけていると、コンバート後のjsと元のhaxeとのマッピングファイルも作成されるので、ブラウザでのブレイクポイントありのステップ実行デバッグが可能となる。

具体的には、haxeのコードに、js.Lib.debug();を入れて実行すると、chromeでは、標準でマッピングがあればそちらを見るようになっているようなので、自分の環境では、そこの行を実行された時に、問題なくデバッガーが起動した。
(もし起動しなければ、chromeの設定がonになっていない可能性もあるので、
https://gist.github.com/jakebellacera/336c4982194bcb02ef8a
を見て確認する)

f:id:suzuki_kuni:20190108183524p:plain
※また、-v をつけてビルドすると、ビルド中の詳細を出力してくれる。

※しばらく使っていると、なぜかコードの内容が表示されないという問題が起こったことがあった。その場合、アプリを閉じて、~/Library/Application Support/Chromeフォルダを削除してから起動することで、再度表示されるようになった。謎だ…。

→その後色々調査が進み、openfl test html5 -debug -D source-map-content

で実行しても再度表示された。

 

 
・as3hxという、ある程度自動的に置き換えてくれる物があるので、それにまず通した。


・またその際、改行コードは、CR改行だとかなり変になることがあったのでLFに変換してから行った(当方mac環境)


・as3hxは、hxのライブラリ群もあって、それを使うように置き換えることもするので、最終的に動かしたいものにはそのライブラリも入れておく。

f:id:suzuki_kuni:20181223110556p:plain

 

・AS3HX WARNING というのが自動変換で付くことがあるが、そこは確認して修正した方が良い。こちらでは、objectとしてなんでも入れてしまっているような変数があって、そこに対して出ていた。

・また、自動的に、
Reflect.field(this, LABEL_ONE)
みたいに、Reflect.fieldで置き換えられる箇所があるが、返り値がDynamicなので、
これに対してのプロパティアクセスは、型の情報がないのでnullが返ってきてしまう。
getChildByNameに変更したのち、castする必要が出てくる。
(Reflect.fieldの返り値をそのままcastすればいいのではと思ったが、それではダメかも?getChildByNameで取得した上でcastしないと、想定の動きにならなかった。詳細までは調べきれず…)

自動変換の後、Reflect.fieldで一度検索して、少なくとも、mc的に使われている部分は、コードを修正した方がいいと思われる。

 


・if (object == _mc.btn_OK)
//次の画面に行く{

 

みたいにコメントを巻き込んで、カッコを下に改行して変換してしまうことがあり、ビルドするとエラーが起こっていた。

 

if (object == _mc.btn_OK){
//次の画面に行く

 

というように普通に修正。

 


haxeの基本的なことになってしまうと思うが、if文で、
if(obj){ //objが存在していたら(falseでなければ)
みたいな判定は出来ない。やりたければ、
if(obj != null){
みたいに、nullかどうかをきちんと見る必要がある。
(あくまで判定はbool型である必要があるということだと思う)

 

※ただその際注意が必要なのが、上記は、「nullかどうか」を見たい場合で、

「trueかfalseか」を見たい場合ではないということ。

 

具体的には、上記のようなコードだと、falseの場合も、

 

if (obj != null){

  //nullじゃない場合。つまり、trueであろうがfalseであろうが入ってしまう
}

 

というように条件に含まれてしまう。この場合、trueだけ通したいのであれば、

 

if (obj != null && obj != false){

  //trueの場合に分岐
}

というように、nullに加えて、falseかどうかも見る必要がある。 

nullとfalseは明確に違う、ということですね。

 

 

・Arrayは、Array<Dynamic>と宣言が置き換えられるが、Dynamicではなく、きちんと型を指定出来るのであれば、しておいたほうがコンパイルの段階でエラーを出してくれるので、トータルで見たらメリットは大きい。出来れば変換後の段階でやっておきたい。
特に、swfファイルが絡んでくると、どこでエラーが起こっているのかを探すのが本当に大変なので…


・また、Dynamic型だと、例えばas3では何も型を指定しなくても、MovieClipが来るという想定で、型指定をObjectか、もしくは何も指定しなくとも、引数で受け取り、関数内で、mc.name = "aaa" みたいにプロパティに問題なくアクセスできるが、haxeでDynamic型を指定してしまうと、Reflect.fieldのところでも書いたが、実際にオブジェクトがMovieClipでnameプロパティを持っていようと、アクセスした際にnullを返してしまう。
これはMovieClipにcastしてからアクセスすれば問題ない。

面倒だが、Dynamicのところは問題を起こしがちなので、一度全て検索して、型を指定していった方がいい。

 


・new Menu → new Menu()
明確なclass指定にしないとだめだった。
(というか知らなかったが、as3では関数指定のカッコいらないということなのか…?)


flash.events.InvokeEvent
が無い。
(というか、AIR関連の、ローカルのファイルをいじるようなやつとかもないので、消すなりしないとだめ)


tweenerの置き換え必要
haxe版も合ったようだがリンク切れになってしまっている…。
TweenXなどのライブラリがあるのでそういったのに置き換える。

もしくは、<haxelib name="actuate" />というhaxelibライブラリがActuate.tweenというのを持っているようなので、それが良いと思う。
(また、同様に恐らく、png生成などのadobeのライブラリ群もないので、置き換える必要があると思われる)

 

・swfファイルも扱える(リンゲージ設定でクラスを指定し、それをhaxe側でnewすることで生成が可能)が、基本クラスの情報は持っていけない。

持っていけるのは、あくまで、階層の構造、素材とフレームアニメーション(ただし、シェイプトゥイーンアニメーションは持っていけない。最初と最後のフレームだけ出て、間は出ない)、フレームラベル(gotoAndStop("fla上に置いたラベル名") みたいなのは動く。ただし、フレームに書いてしまっているアクションは持っていけない。なのでがっつり書いてしまっているプロジェクトはかなり厳しいと思われる)のみ。

 

とはいえ上記が持っていけるだけでも、かなり凄いことだと思うが…

 

また、フレームスクリプトを多用してしまっているswfの移植も行ったので、その時気付いたことも書き残しておく。

 

・フレームスクリプトの移植には、addFrameScriptで書き直したclassを使うのが良さそう。ただし、addFrameScriptは、最後のフレームに対しては効かないような挙動をしていた

 

・ただ、単純なstop()とかであれば、swfで持っていった際に、フレームスクリプトは効いている気がする…。(が、後述する理由で、よくわからない挙動をするので、ガイドにしておいたほうが無難な気がする)

 

・元々flaにかかれているフレームスクリプトはガイドにしたほうがいいかもしれない。そこで動作を妨げてしまうことが合った(その書かれているフレームスクリプトのせいで、フレームの動きが止まってしまう?そういった場合、大体、chromeの黄色いワーニングが出ていて、そこで動作が止まってしまう模様…)

 

 

・gotoAndStopで飛んだ場合、addFrameScriptで書いておいても実行されない…(gotoAndPlayはok)なのでこちらでは、gotoAndStopをoverrideしてスクリプトを実行させるような基本クラスを作っていた

 

・enterframeで最後のフレームかどうかを常に見て、最後のフレームに来たら何かをする、みたいなプログラムからの監視をしている場合、project.xmlに、<haxedef name="swflite-parent-fps" />を入れておかないと、フレームレートの問題でフレームが飛ばされてしまうことがあるのか、スルーされてしまうことが合った。

上記を入れておけばどんなフレームレートにしても、毎フレームきちんと見ることが出来ていた(※ちなみに、フレームレートは

lime.app.Application.current.window.frameRate = 12;

とかで変更出来る模様。project.xmlの指定はどうも効いていないような気がするが、このようにコードで指定することできちんとfpsは変わっていた)

 


また、flashではよく基本クラスで素材の共通的な動きをまとめるとかやるが、それはどのように持っていくか考えないといけない。

自分の場合は、色々調査したのだが、結局、ビルド後に生成されるhxファイルの継承を一括で書き換えることにした。

 

具体的には、
Export/html5/haxe/_generated/
以下に、swfファイル内でリンゲージ設定が行われているオブジェクトのhxが書き出されるが、一律、extendsがMovieClipになっている。

ここを、flashの方で基本クラスにしているものに書き換えて、もう一度ビルドすれば問題なく動作するようになった。

(※既に作らているファイルは再度生成はしないため。ただしもちろん、swfを書き出し直したりした際は再度作られることとなるので、再度の書き換えが必要。これを毎回やるのは無理なので、別途、flashの方で基本クラスをMovieClip以外に指定しているものを全部リストに書き出すfla内のコマンドを作り、そこから

ed -i '' 's/extends MovieClip/extends framework.ui.NumberMovieClip/' Export/html5/haxe/_generated/s01_02/Button_OK.hx

というような、コンソールから変換できる命令文字列を書き出し、それを、flaの方に変更があって書き出しなおすたびに(とはいえ、flaが変更されることはほぼないが)一括で実行するようにして管理した。

本当は、haxeのマクロなどを使って、ビルドシステムの中に組み込みたかったのだが…時間もないのでこの方法までで断念した)

 

 

 

・Animateでは、

f:id:suzuki_kuni:20181229105614p:plain

をoffにしないと、

Export/html5/haxe/_generated/debug_fla/Inner_6.hx:12: character 19 : Invalid character 0xE3

みたいな、日本語関係文字コードのエラーっぽい物が出てだめだった。また、ここをoffにしないと、どのみち、mcとして扱えない模様(画像は出るが、stopなどの命令が効かなくなる)

最近のAnimateでは新規にファイルを作るとここがデフォルトonのようなので確認したほうがいい。


・swc→swfに変更
(厳密に言えば、swcでもhaxeからの利用は出来るのだが、結局中のswfを取り出さないといけないなど、swfにしたほうが早そうだったので)


中のライブラリで日本語になってしまっている箇所は、英語に置き換えが必要。
また、頭を大文字にしないとだめっぽい?(ただ、全てではない?クラスとして認識されるものだけそうすればいいのかも)

具体的には、

Error: Could not process argument debug_fla.シンボル1_4

invalid character: ?

みたいなエラーが出た。
この場合、実際にExport/html5/haxe/_generated/debug_flaに、シンボル1_4.hxというファイルができているが、その中を見ると、どのflaファイルが元になっているかわかるので、そこを修正する。
(一見、上のエラーだけで、debug.flaにあるはずだと思うが、例えば、違うswcをライブラリパスからのリンクで読んでいる時など、そうではない場合もある

 

また、
--macro:1: character 0 : Package "taisen_animation_fla.enemy2_win_result_29" was not found in any of class paths
みたいなエラーが出てきたら、flashのライブラリのそのアイテム
上記の場合、taisen_animation.flaにある、enemy2_win_resultというアイテムの頭を大文字にする。
(というか、ライブラリ全てに対して、頭を大文字にするとか、頭に固定の大文字をつけるみたいな機能拡張のスクリプトを書けば良いのかも)

 

・flaの中のリンゲージ設定で、パッケージ名をつけている場合、頭が大文字だとだめ。
haxeからは、ここに指定があるとスクリプトファイルとして書き出され、スクリプトから参照できるようになるが、haxeのパッケージ名としては最初大文字では通らないので、コンパイル時にエラーが出る)
小文字にする必要がある。

ただしパッケージ名だからであって、クラス名の最初は大文字じゃないとだめ。

f:id:suzuki_kuni:20181227200324p:plain

その際に一括で変換するには、
http://feb19.jp/blog/archives/000237.php
に、リンゲージ設定の文字列を全て調整できる機能拡張がある。
/Users/xxxxxxx/Library/Application Support/Adobe/Animate CC 2019/ja_JP/Configuration/Commands
に、

Add Prefix to Linkage.jsfl
Add Prefix to Linkage.xml

Remove Prefix from Linkage.jsfl
Remove Prefix from Linkage.xml

を入れると(※再起動の必要もないみたいです)、「コマンド」に出てくる。
上記の例だと、Remove Prefixで1文字消して("S"が消える)、
Add Prefixで小文字のsを頭に追加、ということが一括でできるのでかなり便利。

 


・Dictionaryに型を設定する。
<Dynamic,Dynamic>とかでもいいが、前述の色々なDynamicの問題もあり、明確に型を指定した方が好ましい。

var aaa : Dictionary = new Dictionary();

var aaa : Dictionary<Dynamic,Dynamic> = new Dictionary();
(もしくはMapにしてしまうのでもいいと思う)


flash内に、btn$S01_03
みたいな名前が付いているmcがあり、「$」がコンパイル通らないので、
btn_S01_03に変更。


・Numberを、IntかFloatかにきちんと変更する。
(自動変換だと、Floatにされてしまう模様。Numberは浮動小数点数持てますからね…挙動的には正しい)
Float should be Intというエラーが出る。


・aaa["bbbb" + i].play();
みたいな、文字列で子のmcにアクセスしている部分は、
aaa.getChildByName("bbbb" + i).play();
に置き換える。


同様に、mcA.childMc.gotoAndStop(1);
みたいにしている箇所は、flashでは暗黙的にエラーを出さないでいてくれるが、
haxeではエラーになる。
mcA.getChildByName("childMc").gotoAndStop(1);
みたいにする必要がある。


・openfl.display.DisplayObject should be flash.display.MovieClip
MovieClipにcastする。


・Unknown identifier : arguments
http://mmmpa.hatenablog.com/entry/2014/12/22/Haxe_で無名関数を_arguments.callee_でアレしようと思ったらダメだ
arguments.calleeの置き換えが必要。


・Too many arguments
private var tmpStatus_ : Array<Dynamic> = new Array<Dynamic>(10)

private var tmpStatus_ : Array<Dynamic> = new Array<Dynamic>()

 

・as3で、
var className:String = getQualifiedClassName(someMC);
という箇所は、
var className : String = Type.getClassName(someMC);
というように自動変換されるが、そこから更に、
var className : String = Type.getClassName(Type.getClass(someMC));
というようにしないとコンパイル通らなかった。

 

・同様にas3で、
var c:Class = Class(getDefinitionByName(className));
という箇所は、

var c : Class<Dynamic> = cast( (Type.resolveClass(className)), Class);
というように自動変換されるが、
var c : Class<Dynamic> = Type.resolveClass(className);
でokだった。

 

 

・as3だと、例えば、

var array = [1];

var test = String(array);

とすると1になるが、haxeの場合はStd.stringに置き換えると思うが、

var test = Std.string(array);

とすると、"[1]"という、配列をそのまま文字列に変換したような、カッコまで文字列化されてしまう。

 

この場合、

var test = Std.string(array[0]);

と明確に位置まで指定して文字列にする必要がある。

 

 

・for( var i:Number=0; i<=2; i++ ){
というfor文(3回ループする)があるとしたら、それは、
for (i in 0...2) {
に置き換わる…。が、実際には
for (i in 0...3) {
じゃないと、3回のループにならない。

これ地味に物凄く気づきにくいのので注意する…。

 

haxeのgotoAndStop()は、stop()も同時に呼び出している(asではそうではない)。なので、 例えば、
override public function stop() : Void
というように、mcを継承した独自classでstopをoverrideして使っている場合、そちらも呼び出されてしまう。


・ブラウザ起動まで行くものの、
var symbol = swfLite.symbols.h[29];var symbol = swfLite.symbols.h[29];
undefined is not an object (evaluating 'swfLite.symbols')

というエラーが起動時に出て止まってしまった…。色々調べたところ、
private static var _soundPanel : SoundPanel = new SoundPanel();

private var _soundPanel : SoundPanel = new SoundPanel();
というように変えたら大丈夫だった。

このSoundPanelの中では、swfファイルのオブジェクトを継承して使っており、
staticでswfファイルの中身を見るようなものはだめなのかも…?(検証してませんが…)

 

・ブラウザ起動まで行くものの、
RangeError: Maximum call stack size exceeded.
で落ちる。

再帰でループしている箇所があると思われるので確認。(jsには最大で呼び出せる関数の数というのがあるが、ループして、それを使い尽くしてしまっているという状態。

https://qiita.com/LightSpeedC/items/cff177ec013bd11d12af

などを拝見させていただく限りでは、IEでは以外に少なく、超巨大かつリロードとかなくずっと動く、というような物を作るのはかなり危険なのかもしれない…)

 

WebGL: INVALID_VALUE: texImage2D: no canvas

[.WebGL-0x7f9f4701d800]RENDER WARNING: texture bound to texture unit 0 is not renderable. It maybe non-power-of-2 and have incompatible texture filtering.

みたいなエラーが出る。

これは、x,y,rotationなどの値に、NaNやnullを渡してしまっている可能性が非常に高いのでその辺りから追っていく。

 

・0xff0000,0x00ff00などの色指定は、Intで持ったほうがいい。mc.graphics.lineStyle(width, color, 100);のようにした時の変数colorがfloatだと、特にエラーも何も出ないし数字が変化するということも無いのだが、なぜか、色が変わらなかった。

 

・ありがちな以下のようなスクリプト

private function onNumBtnPress(e : MouseEvent) : Void
{
var num : Int = e.currentTarget.name.split("_");
...
}

private function onNumBtnPress(e : MouseEvent) : Void
{
var num : Int = cast(e.currentTarget, MovieClip).name.split("_");
...
}

のように、MouseEventのcurrentTargetはDynamicなのでmcへのキャストが必要。

(Dynamicはほんと、エラーも何も出ないのでめちゃくちゃ厄介…)

 

・たまに、fla上に置かれているシェイプが上手く出ないことが合ったが、レイヤーを分割して置き直してみる事で改善することが合った。

 

また何かあればこちらに書いていきます。

GoogleVRForUnityのinstant previewが始まらない…

起動はしているものの、connectの種類を選択してくれ、その後unity側でstartを押してくれという画面から進まなかったが、

 

answers.unity.com

 

に書いてあるとおり、カメラに「MainCamera」タグを付けていなかったのが原因で、付けたところプレビューできるようになりました。

Laravel ページを開くと500エラー…

sudo chmod -R 777 storage

で解決。

 

ストレージディレクトリの権限の問題だった。

以前も同じようなエラーが出て解決したはずなのに、すっかり忘れてしまっていた…。

【Laravel5.0/php5.4】Symfony\Component\Debug\Exception\FatalErrorException Uncaught TypeError: Argument 1 passed to App\Exceptions\Handler::report()

Laravel5.0で、

php artisan migrate:refresh --seed
を実行すると、

 

[Symfony\Component\Debug\Exception\FatalErrorException]                      
  Uncaught TypeError: Argument 1 passed to App\Exceptions\Handler::report() must be an instance of Exception, instance of Error given, called in xxx/vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/HandleExceptions.php on line 73 and defined in xxx/app/Exceptions/Handler.php:25

 

というエラーが…。
composer dump-autoloadしても直らず。


結局、php my adminからテーブルを一旦消して、作り直して、再度
php artisan migrate:refresh --seed
の実行で問題がなくなった。