JavaScriptわからない

qiita.com

これ便利そうなんだけど、reduceとかどうしてそうなるのかがよくわからない。
いや、正確に言うとじっくり式を見てみれば何をやっているのかはわかるんだけど、なぜそのやり方でやらないといけないのかがわからない。
ES2015では当たり前のやり方なのだろうか? 読みにくくないか? そういうもんなのか。。?

あとJavaScriptというかjQueryなんだけど、何でeachの引数の順番がforEachと違うのだ。

qiita.com

forじゃなくてeachなんだから敢えてインデックス使うことは少ない。でもインデックスが先に来ちゃってるから、インデックス使わないときも$(something).each(i, e)とか書かないといけない。使うのはeだけだ。

あと、なんでこんなに広まっている言語なのに基本的な関数がなかったりするのか。
なんでゼロパディングを自分で作らないといけないのか。
forEachはどうしてオブジェクトを回してくれないのか。

JavaScriptは難しい。こういうのに慣れれば楽しいんだろうなとは思うけれども。。

delegateを配列に入れる

DB上にあるレコードの数だけインスタンスを作って、それを何か別のクラスのデリゲートにしたいという時がある。そういう時、デリゲートを動的に配列に入れたくなると思う。

それをやろうと思って、NSMutableArrayにdelegateを入れようとしたらダメだった。 いろいろネットを検索して、以下のようなやり方があるのを見つけた。

プロトコル | Swift言語を学ぶ

delegateをNSMutableArrayに入れようとしたらできなかった。これみたらvar someDelegates:[SomeDelegate] = [] と宣言してそいつにsomeDelegates.append(someDelegate) としてやれば入るっぽい。というかできた。

2015/09/09 11:39

NSMutableArrayではなくて、なんかクラス名を[]で囲むタイプの配列を使えばいいらしい。

自分は以下のように書いた。

// メンバ変数で配列を宣言
var delegates:[SomeDelegate] = []

/* 中略 */

  // delegateの宣言
  var delegate:SomeDelegate = someObject
  // 配列にdelegateを追加する
  delegates.append(delegate)

/* 配列に入ったデリゲートに一斉になんか命令を飛ばす */

  for i in 0..<delegates.count
  {
    delegates[i].someMethod()
  }

こんな感じでやれば一斉に動いたのでうれしかったです。

SwiftでhitTestのイベント透過

Objective-CにはhitTestというメソッドがあって、それを使えばそのビューを透過して下のビューのイベントを動作させることができていた。

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    UIView *view = [super hitTest:point withEvent:event];
    if (view == self)
    {
        return nil;
    }
    return view;
}

こういうの。 Swiftでそのまま同じコード書いたらビルドエラーが出た。 オプショナル型をちゃんと理解してればこんなのは簡単にSwiftで書けるんだろうけど、自分は全く分かっていなかったので30分くらい試行錯誤してしまった。。

Swiftでは以下のように書いたら動いた。

override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
    var hitView:UIView? = super.hitTest(point, withEvent: event)
    if(self == hitView)
    {
        return nil
    }
    return hitView
}

UIViewの宣言をオプショナル型でするだけだった。。

whereについて

今までiOSアプリのプログラミングにはObjective-Cを使っていたのだが、ようやくSwiftを勉強する仕儀となった。

そこでアップルのドキュメントを読んでいたのだが、こういうのを見つけた。

let vegetable = "red pepper"
switch vegetable {
case "celery":
    let vegetableComment = "Add some raisins and make ants on a log."
case "cucumber", "watercress":
    let vegetableComment = "That would make a good tea sandwich."
case let x where x.hasSuffix("pepper"):
    let vegetableComment = "Is it a spicy \(x)?"
default:
    let vegetableComment = "Everything tastes good in soup."
}

わからなかったのは、

case let x where x.hasSuffix("pepper"):

と書いてある「where」の部分。SQL文でWHERE句というのはよく使うが、それ以外でwhereは初めて見たかもしれない。
他の言語でも使えるのだろうか。

アップルのドキュメントにはwhereの説明とか別になかったから、他の言語でもきっとあるのだろう。
意味的には絞り込みという感じでSQL文のWHEREと似たような感じなのだろう。

とか思ってたら同じような疑問を抱いた人は既にいた。

stackoverflow.com

どうやらSwift独特の文法らしい。

GMSMapViewの上に自分で作ったUIViewとかを配置する方法

GMSMapViewの上には通常マーカーとかのAPIから提供されてるオブジェクトしか置けない。

しかし、マーカーのとなりに常にインフォウィンドウ的なのを表示させておきたい場合もある。マーカーにはデフォルトでインフォウィンドウがあって、タップして選択すると表示されるが、マップ中のどれか一つのマーカーのインフォウィンドウしか出ない。でも画面内にあるマーカーはどれもインフォウィンドウ開きっぱなしにしたい場合もある。

擬似的にそういう画面を作る方法があったのでメモしておく。

まず、GMSMapView中のマーカーの緯度経度を、画面上の座標に変換する必要がある。変換にはGMSMapViewのプロパティであるところの(GMSProjection *)projectionを用いる。

マーカーのクラスとかに、

CGPoint point = [self.map.projection pointForCoordinate:self.position];

などとおもむろに書き込んで座標を取得する。 しかるのちにUIViewなどの欲しい部品を設定する。

UIView *myView = [[UIView alloc]initWithFrame:CGRectMake(point.x, point.y, 100, 50)];
myView.backgroundColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:1];
UILabel *myLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 100, 50)];
myLabel.text = @"テスト";
[myView addSubview:myLabel];

これにより幅100、高さ50のインフォウィンドウもどきが設定された。

これをマップビューにaddSubviewすればインフォウィンドウもどきが表示されるはずである。 が、マップを移動したりとか拡大縮小したりするとマーカーの位置とずれる。このインフォウィンドウは画面の座標に貼り付けてあるから当然なのだが、自分の場合は何秒かに一回removeFromSuperviewして再度新しい座標を取得して配置し直すことで擬似的に表現している。あるいはマップビューが止まった時のデリゲートメソッド- mapView:idleAtCameraPosition: を使ってもまあまあ許容範囲という感じだ。

for (int i = 1; i < self.mapView.subviews.count; i++)
    {
        [self.mapView.subviews[i] removeFromSuperview];
    }

こんな感じでビューを消すと意図した通りになる気がする。int i = 0 から始めるとマップビューまで消えて面白い感じになる。

アルフレッド・ベスターの『虎よ、虎よ!』を読んだ

長大なSSを読んだような気持ちがした。しかも結構クソ的なテイストの。面白くなかったというわけではないのだが。。これが50年代のSFかぁ、と感じた。

GMSMapViewの回転

端末が回転したときにGMSMapViewもそれに合わせてサイズを変えたいと思って色々調べた。

qiita.com

そしたら- willAnimateRotationToInterfaceOrientation:duration: というメソッドが引っかかったのだが、これはiOS8.0以降deprecatedらしく- viewWillTransitionToSize: withTransitionCoordinator: というメソッドを代わりに使うべきなのらしい。

その中にどういう処理を書けば自動でリサイズできるのか色々調べていたら、以下のような記事を見つけた。

http://www.zero4racer.com/blog/988www.zero4racer.com

aroundthedistance.hatenadiary.jp

自分はGMSMapViewをUIViewのサブビューに突っ込んでやればオートレイアウトが効いて回転するかと思ってたらUIViewだけ効いててGMSMapViewはそのままだったので、手動でGMSMapViewのサイズをUIViewと揃えてやろうとしたらなぜか初っ端からずれる。その原因は上記2つの記事にあるように、オートレイアウト後のサイズはViewDidLoadのときには取得できないのであるらしいことによるものだった。

結局、以下のような書き方をした。

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
    CGRect new = CGRectMake(0,0,size.width,size.height);
    self.mapView.frame = new;
}