さるへい備忘録

さるへいのやったことを綴っているブログです。基本的にテクノロジーの話題です。

Pythonでコロンなどの引数のパラメータ名に使えない文字を無理やり引数のパラメータ名に指定する方法

Pythonで引数にコロンなどの利用できない文字を含めたパラメータ名で呼び出したいといった場合がありませんか?
どういう意味かわからないって顔をしている人が多そうです。

sample(ho:ge='hoge')

みたいな感じで呼び出したいってことですね。
もちろん上記はエラーが出ます。

そういう設計にしなければ良い?ええそれが一番だと思います。

ですが、時間の制約と求められている仕様によっては仕方がないときが多々あります。
RSSのパラメータ名などを表現する場合など仕方ない時もありますね。

辞書の展開で渡す

実際に引数に指定するとエラーになるならば、動的に生成して無理やり渡せばいいじゃないというのが僕の結論です。

def sample(**kwargs): # 可変長引数
    print(kwargs)
    

sample(**{'ho:ge': 'hoge'})  # 辞書の展開 
 -> {'ho:ge': 'hoge'} # こちらは出力

上記は、sampleメソッドに実際にコロンを含めた文字列を渡した場合です。
辞書の展開を使うことによって無理やり渡しました。
このようにすればメソッド呼び出し時にコロンなどをつけたパラメータ名を指定できます。

もちろん、メソッドの定義側は可変長引数で受け取る場合でしかこのような事象は発生しません。

iOSアプリでTableViewを実装しようとしたら表示されなかった。TableViewに限らずなにも表示されない時の原因について

みなさんTableViewつかってますか? アプリを作る上でTableViewは欠かせない要素だと思います。

そんなTableViewが急に一切表示されなくなったということがありました。 cellの生成メソッドは問題なく呼ばれているのになぜ?という感じでしたが、原因がわかったので紹介します。

キーポイントはconstraintなどのサイズ調整

TableViewが表示されない悲劇は作成してたアプリのデフォルトiPhoneのサイズが変わった時に発生しました。

何も表示されないぞ?と思ってstoryboardを見たらこうなってたんですね。

f:id:saruhei1989:20190312081424p:plain
飛び出るTableView

とはいえ、中途半端に出るだろさすがにと思って特に処置せず他の原因を求めたのですが全く駄目。
まさか・・・?とおもってTableViewをViewControllerの中に収めたらあら不思議。きれいに表示されました。

うまく調べられず全然仕組みまで追えてないですが、とりあえず親要素をはみ出すなよ?って話ですね

これはきっとTableViewに限った話じゃないので、iOSアプリを作成する際には気をつけましょう。

iOSアプリでfirebaseを導入したはずなのにうまくいかないよといったことへのtips

今やiOSアプリを作る際はfirebaseを導入するでしょう!といった雰囲気があります。
firebaseは無料で使える非常に優秀なツールなのでたしかに入れない理由はありません。

ですが、 (https://firebase.google.com/docs/ios/setup?hl=ja) の通りに導入したのに全然うまくいかないよ!
みたいな人もいると思います。
はい。僕のことですね。

そんな僕みたいな人に向けた、 firebase導入時のハマりポイントを紹介します。

GoogleService-Info.plistがうまく認識されないよ!

具体的に以下のようなエラーがひたすら出続ける状況のことです。

reason: 'Configuration fails. It may be caused by an invalid GOOGLE_APP_ID in GoogleService-Info.plist or set in the customized options

こちらのエラーですが、具体的には GoogleService-Info.plist が見つからないといった場合も発生します。
解決方法としては、以下のリンクがわかりやすいですね。

stackoverflow.com

プロジェクトのrootに設置しなければいけないのに、 Xcodeさんの新設設計によってresource ディレクトリに設置されちゃうやつです。
実際にFinderなどで確認してみると良いです。

ちなみに僕はこれを処置したあとも謎に出続けて、腹が立ってもう一回設置しなおしたら動きました。
なんででしょうね。

うまくfirebase読み込まれているはずなのに、管理画面で全然反映されない

僕は2時間かかりました。以上です。

firebaseを導入したい人へ何かの助けになれば幸いです。

swiftとsegueで画面遷移のやりかた

iOSの開発で誰しもが困るポイント「画面遷移」

segueを使って実装したらかなり楽でした。 以下のようなやりかたで実現できます。

1. 遷移先のView Controller作成

storyboardからView Controllerをもう一つ作成しましょう

2. 遷移元のView Controllerと遷移先のView Controllerをsegueで接続

Ctrl + ドラッグで繋げられます。
僕は個人的に左の欄からつなげるのが好きです。(名前をよく知らない)
画面を直接ドラッグでひもづけるとうまくView Controllerを触れない僕がいました。 f:id:saruhei1989:20150906135517p:plain

そうすると、以下の表示がでて、遷移のアニメーションを選択できるのでどれかを選びましょう。 僕は個人的にshowが好きです。 f:id:saruhei1989:20150906135916p:plain

そうすると、以下のようにsegueで接続されます。 f:id:saruhei1989:20150906140028p:plain

segueには、identifierを登録しましょう。遷移の際に必要になります。 f:id:saruhei1989:20150906140244p:plain

3. 遷移のコードを記述します。

遷移元のView Controllerに以下のコードを記述すると、遷移が実行されます。
遷移させたいタイミングで記述しましょう。

//identifierを記述するところには、先ほど登録したsegueのidentifierを記述する
performSegue(withIdentifier: "seguetest", sender: self)

また、遷移する際になにか処理をさせたい場合には、以下のコールバックメソッドにて処理を記述できます。

override func prepare(segue: UIStoryboardSegue, sender: Any?) {
    // 処理を実行したいsegueを指定
    if segue.identifier == "seguetest"{
        //遷移先のインスタンスをsegueから取り出す
        let nextViewController: hogehogeViewController = segue.destinationViewController as! hogehogeViewController
        //ここでいろいろ処理みたいなことをする
    }
}

上記メソッドは、各View Controllerに一つしか書けないので、複数のsegue遷移がある場合は、if文などでsegueのidentifierを指定すると良いでしょう。

やはりstoryboardは優秀ですね。(こなみかん

追記 2019/03/12 swiftの文法が変わっていたので最新のものに修正

SELinuxが原因の通信遮断の原因判定から、audit2allowでnginxなどを許可するまで。

外部と通信しているアプリケーションの場合、通信できない原因はSELinuxを疑ってみると原因がSELinuxであることが多々あります。
でもSELinuxってなかなか難しいですよね。
web上を探してもあんまり資料が落ちてないし、そもそも疑うエラーログからは全然SELinuxが原因であることがわからない上に理由もわからないみたいなことばっかりです。

SELinuxでの原因判定方法

なんとなくSELinuxのせいかな?なんて思った場合は、一回SELinuxを切って確認してみると良いです。

まず、SELinuxが可動しているか確認してみましょう。

$ getenforce
Enforcing

上記のように Enforcing と出た場合はSELinuxが有効であることの証拠です。
Enforcing と出ない場合はSELinuxが可動していないので、エラーの原因は他にあります。

$ setenforce 0
$ getenforce
Permissive

上記のようにSELinuxを無効にすることができます。 その後、稼働状態を確認して、 Permissive であることを確認しましょう。 この状態でアプリケーションで通信などをしてみて有効状態でできなかった動作が成功した場合はSELinuxが原因であることの証拠です。

確認後はもちろんSELinuxを有効に戻しておきましょう。

$ setenforce 1
$ getenforce
Enforcing

audit2allowでSELinuxのポリシーモジュールを作って解決

SELinuxが原因というところまではなんとか辿り着く人もいるのですが、この後どうすればいいかわからないといった人をよく見かけます。
そんな時に便利なのが audit2allow (https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/6/html/security-enhanced_linux/sect-security-enhanced_linux-fixing_problems-allowing_access_audit2allow)

こちら、SELinuxの拒否操作ログからSElinuxのポリシーallowルールを作成できるすぐれものです。 ただ、こちらなんでもかんでも許可してしまうとSELinuxの意味がなくなってしまうので、慎重に行うと良いでしょう。

nginxとSELinux

nginxは、SELinuxが原因でsockの書き込み権限などが制限されていて、 sockファイルを使った通信などができません。
以下のようなエラーログが吐き出されている場合はSELinuxが原因である場合があります。

2019/02/25 00:18:15 [crit] xxxxx#0: *xxxx connect() to unix:/path/to/sock.sock failed (13: Permission denied) while connecting to upstream, client: ipアドレス, server: 設定server名, request: "GET / HTTP/1.1", upstream: "サーバアプリ://unix:/path/to/sock.sock:", host: "ホスト名"

こちらをでnginxに対して限定的にSELinuxのポリシーallowルールを作ることでnginxを使った通信が可能となります。  

$ cat /var/log/audit/audit.log | grep nginx | audit2allow -m nginx
module nginx 1.0;

require {
        type unconfined_t;
        type httpd_t;
        type user_home_t;
        class sock_file write;
        class unix_stream_socket connectto;
}

#============= httpd_t ==============
allow httpd_t unconfined_t:unix_stream_socket connectto;
allow httpd_t user_home_t:sock_file write;

上記は、/var/log/audit/audit.logaudit.logが存在していると仮定した場合のコマンドです。
こちらのコマンドで、 nginxへの解決にgrepしてどんなポリシーallowルールが適用されるか確認しましょう。
上記で大丈夫が確認することが大事です。

大丈夫そうだったら下記コマンドで実際にポリシーallowルールをコンパイルして適用するためのバイナリファイルを作成しましょう。

$ cat /var/log/audit/audit.log | grep nginx | audit2allow -M nginx
******************** IMPORTANT ***********************
To make this policy package active, execute:

semodule -i nginx.pp

nginx.pp として作成されるので、下記コマンドで適用しましょう。

$ semodule -i nginx.pp

これで、現在nginxがSELinuxにブロックされていた原因を取り除くことができます。
ただ、ブロックを取り除いた上で更に別のSELinux上のセキュリティ機能にブロックされることもあります。
その場合は、また同じことをしてポリシーallowルールを作成すると良いでしょう。

上記は、nginx以外にもいろいろ使えますが乱用すると非常に危険なコマンドです。
くれぐれも何が起こるかをしっかり見極めて適用していきましょう。

Pythonの動的なモジュールとクラスのインポートからのインスタンス生成方法

Pythonでモジュールの動的なインポートからのインスタンス生成をしたので紹介します。 クラスだけ動的に生成はけっこうあるんですが、モジュールの動的インポートって結構レアみたいですね。 IDEとかでエラーが見えづらくなるので、そこは注意してくださいね。

実際のコード

# coding: utf-8

import importlib


module_path = 'importするモジュールのパス'
module = importlib.import_module(module_path) # モジュールのインポート
Klass = getattr(module, '生成したいインスタンスのクラス') # クラスの取得
Klass(hoge='fuga') # インスタンス生成

こう書いてしまうと結構簡単ですね。 なんかこう、素敵な仕組みを作れそうだったらガンガン作ってください。

ただ、前述の通りIDEでエラーは検知しづらい上に、コードが複雑になりやすいです。 十分に仕組みを検討の上で利用したほうが良いでしょう。

僕は使いましたが、正直将来バグを生みそうで怖いです。

iOSアプリを作ってる時にBar Button Itemからsegueを繋げないのにさっぱり反応しない時の原因

iOSアプリを作ってる時にナビゲーションバーにボタンを設置して、そこから前の画面へ遷移したりすることはよくあると思います。

f:id:saruhei1989:20190306081227p:plain
こんなやつ

そんな時に事件は起こりました。
segueをつなげてさあ別のページへ遷移!と設定したんですが、全然動かない。。。。
あまりに動かないので、画面の真ん中にボタンを設置してsegueつなげてみたら動いてなんだこれは。。。となりました

原因はBar Button Item

f:id:saruhei1989:20190306081530p:plain
なんかたくさんパーツとかでてくる画面(名前は忘れた)

ナビゲーションバーにボタンを設置する時、上記みたいにBar Button Itemとして設置されると思います。 そう。Bar Button Itemはボタンじゃないので、ここからsegueつなげても駄目なんですね。ちゃんと メニュー ってなってるButtonのほうからつなげましょう。
ボタンの文字列が書いてあるので、わかるまでずっとただのラベル的な何かだと思ってました。
ちょっと考えれば当たり前ですね。でも結構気が付かないものです。

XcodeとかSwiftの更新とかでついていけなくなるよりも、5年ぶりに触った僕はこういった初歩的なところでハマりまくりでした。