面白きことは良きことなり

拙く未熟なiOSエンジニアの備忘録と戯言

JavaScriptでTextBoxに入力された内容からリンクを生成

仕事でURLSchemeのテストをする際、
TextBoxに入力された値からリンクを生成したかったので調べて作ったのを記載。

<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <header>
    </header>
    <body>
    <form name="form1" id="id_form1" action="">
        <input name="textBox1" id="id_textBox1" type="text" value="" placeholder="文字列入力"/ size="45">
        <input type="button" value="リンク生成" onclick="onButtonClick();" />
    </form>
    <div id="link"></div>
    <script type="text/javascript" language="javascript">
    function onButtonClick() {
        var object = document.getElementById('link');
        var tag = document.createElement('a');
        tag.setAttribute('href','http://'+document.forms.id_form1.id_textBox1.value);
        tag.appendChild(document.createTextNode('リンク'));
        // 生成するたびにリンクが増えるのを防ぐため削除
        if (object.childNodes.item(0)) {
            object.removeChild(object.childNodes.item(0));
        }
        object.appendChild(tag);
    }
    </script>
    </body>
</html>

Swift2のguard let構文で順序を意識せずクラッシュする書き方をしていた話

Swift2のプロジェクトの話
NSTimerを扱う処理を書いており、userInfoにBool値を渡して、後から安全にキャストして取り出す処理をguard letを使って下記のように書いていた。

// Swift2
// before
func hoge(timer: NSTimer?) {
    guard let timer = timer, flag = timer.userInfo as? Bool where timer.valid else {
        return
    }
    print(flag)
}

しかし、timer.invalid()を呼んだ後だとreturnで返る前にクラッシュしていた。


修正後は下記のように記述。

// Swift2
// after
func hoge(timer: NSTimer?) {
    guard let timer = timer where timer.valid, let flag = timer.userInfo as? Bool else {
        return
    }
    print(flag)
}

自分の解釈ではwhereは末尾につけなければいけないと思い込んでいたがために、timer.invalid()でuserInfoがnilになっているにも関わらず、timerから取り出そうとしてクラッシュしていた。

なので、timerをOptional Bindingで取り出した後、whereで条件を判定させるように変更した。

PlaygroundでPage追加

小ネタ程度の話。
自分が知ったのは少し前だったので、
少数ながらも意外に知らない人もいるのでは?と思ったので、書いておく。


Playground自体Swiftの記述でテストや検証に簡易的に扱えることもあり、
頻繁に使うと思うのだけれど、色々書きすぎてプレビューの表示が遅くなることもしばしば。
そのたびに新しいPlaygroundを作るという無駄にファイルを生成する行為をしていたが、1Playground内にPageを追加できるので記載。

Page追加前

f:id:aryzae:20161204175914p:plain

Page追加 (XcodeのFile > New > Playground Page)

f:id:aryzae:20161204180111p:plain

Page追加後

f:id:aryzae:20161204180210p:plain

Playgroundの左カラムで右クリックから追加できたらいいんだけどな。
なぜかできない・・。

Scheme呼び出しで://の//をリンク形式でなら省略することができる

スマホアプリはでよく使う機能にSchemeがあると思う。

jp.co.hoge://paramのような形式でアプリにあらかじめ登録しておくと、
スマホのブラウザから上記アドレスを呼び出すことでアプリを起動させ、
パラメーターによって処理を行わせる。

このSchemeで//を省略して呼び出せるという話を聞いたので、
知らなかったため記載。

リンク形式で下記のようにかける。
(mailto:とかと同じ書き方なだけ)

<!-- //省略して書いても動作する -->
<a href="jp.co.hoge:param">//省略りんく</a>

<!-- 別に省略しなくても問題はない -->
<a href="jp.co.hoge://param">りんく</a>

ただ、個人的に言わせれば、//がないと区切りがわかりづらいので、
見た目としては//あったほうがいいと感じる。
それに//省略したからなんだという話に・・・。

知識の片隅程度にあれば役に立つ時があるかもね。

NSTimerでinitとscheduledTimerWithTimeIntervalは別物ということを知った話

NSTimerで処理を書いた際、repeatsをtrueにしているのに繰り返し処理してくれないで悩んだことがあった。

initメソッドの

public /*not inherited*/ init(timeInterval ti: NSTimeInterval, target aTarget: AnyObject, selector aSelector: Selector, userInfo: AnyObject?, repeats yesOrNo: Bool)

とclassメソッドの

public class func scheduledTimerWithTimeInterval(ti: NSTimeInterval, target aTarget: AnyObject, selector aSelector: Selector, userInfo: AnyObject?, repeats yesOrNo: Bool) -> NSTimer

は別物ということを教わった。
昔やった気もするし、今更な話ではあるが。


処理の違いとして下記の差がある。両方は同じ処理をする作りとなっている。

// 自動発火&自動repeat
let timer = NSTimer.scheduledTimerWithTimeInterval(0.5,
                                                   target: self,
                                                   selector: #selector(hoge),
                                                   userInfo: nil,
                                                   repeats: true)
// repeatさせない際、fire()で発火必要
// repeatさせる際、NSRunLoopを使用する処理が必須(自動発火するのでfire()は不要)
let timer = NSTimer(timeInterval: 0.5,
                    target: self,
                    selector: #selector(hoge),
                    userInfo: nil,
                    repeats: true)
let runLoop = NSRunLoop.currentRunLoop()
runLoop.addTimer(timer, forMode: NSRunLoopCommonModes)