TKC Works

ギジュツ的なメモ、読書感想文など

Swiftで分割したStoryboardの呼び出し方

チームでアプリを開発する場合や一つのStoryboardが大きくなりすぎるのが嫌な場合など、Storyboardを分割したくなるけど、じゃあどうやって呼び出すの?となるので書いておく。

  • 基本的にはObjective-Cの時と同じ
  • UINavigationControllerを使っている場合はちょっと違うので注意
  • Storyboard上でIs Initial View Controllerのチェックを入れるのを忘れずに
//UIViewControllerの場合
@IBAction func hogeButtonTapped(sender: AnyObject) {
    let story = UIStoryboard(name: "Hoge", bundle: nil)
    let vc = story.instantiateInitialViewController() as HogeViewController
    self.presentViewController(vc, animated: true, completion: nil)
}

//UINavigationControllerの場合
@IBAction func hogeButtonTapped(sender: AnyObject) {
    let story = UIStoryboard(name: "Hoge", bundle: nil)
    let nc = story.instantiateInitialViewController() as UINavigationController
    self.presentViewController(nc, animated: true, completion: nil)
}

ファイル単位でARCを有効にする

ファイル単位でARCを有効にする

cocos2d-xでもSocket.IOでリアルタイム通信をやろうとした場合、
v3には標準のクラスに追加されたからそれを使えばなんとかなる。
ただし、Socket.IOのバージョンは0.9で1.0には対応してないしWebSocketオンリー。

C++でよいライブラリはないか探したけど見つからないので、
iOSからはこのobj-cのライブラリを使うことにした。
https://github.com/pkyeck/socket.IO-objc

ただし、一部ARCを有効にしないといけないファイルがあり、

//SocketRocket/SRWebSocket.m
#error SocketRocket must be compiled with ARC enabled

cocos2d-xで作成したプロジェクトは基本無効になっているためどうしようかと思っていたら、
ファイルごとに設定出来ることを発見。

Build Phases > Compile Sources で対象ファイルに-fobjc-arcを指定すればOK。

こちらを参考にさせて頂いた。
http://lab.dolice.net/blog/2013/05/10/objc-arc-switch/

UnityでiOSでもAndroidでもSocket.IOでリアルタイム通信

僕は別にアプリエンジニアじゃなかったんだけど、やらないといけなくなり、検証したのでメモ。
(Node.jsはv0.10.28、Socket.IOは0.9.17、Unityは4.3.4、iOSは7.1.2、Androidは4.4.2で検証)

スマホでSocket.IOを使いたい場合、ネイティブではこの辺のライブラリを使うと思う。
https://github.com/pkyeck/socket.IO-objc
https://github.com/Gottox/socket.io-java-client

ネイティブプラグインはよくわからなかったのでC#で書いてiOS,Android両方で使えるのはないかなと思っていたら
https://github.com/NetEase/UnitySocketIO
これが見つかった。他にはあまりなさそう。

で、一個問題があって、iOSだとEXC_BAD_ACCESSやら--aot-onlyと言われてうまく動かない。
SimpleJson.dllが古い、かつiOSでは使えないオプションが付いていたみたいなので、
SimpleJsonを自分でビルドし直した。
SimpleJson.csで#define SIMPLE_JSON_NO_LINQ_EXPRESSIONをアンコメントする必要がある。

ここが参考になった。
https://github.com/kaistseo/UnitySocketIO-WebSocketSharp
こっち使ってもよかったかも。
まあどちらにしてもSocket.IOといいつつWebSocketしか使えないし、1.0系に対応するかどうかはよくわからない。。

ちなみにDLLを更新した版はフォークしてここに置いた。
https://github.com/take4/UnitySocketIO

C#のサンプルコード※サーバー側はよくあるサンプルチャットなので割愛。

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class NewBehaviourScript : MonoBehaviour {
    public GUIText text1;
    public string text = "";
    SocketIOClient.Client socket;

    // Use this for initialization
    void Start () {
        Debug.Log ("start");

        socket = new SocketIOClient.Client ("http://xxx.xxx.xxx.xxx:3000/"); 
        
        socket.On ("connect", (fn) => {
            Debug.Log("connect - socket");

        });
        
        socket.On ("message:receive", (data) => {
            Debug.Log(data.Json.ToJsonString());
            text = data.Json.ToJsonString() + "\n" + text;
        }); 
        
        socket.Connect();
    }
    
    // Update is called once per frame
    void Update () {
        text1.text = text;
    
    }

    void OnGUI() {
        if (GUI.Button( new Rect (30, 30, 120, 50), "PUSH")) {
            Dictionary<string, string> args = new Dictionary<string, string>();
            args.Add("message", "YO");
            socket.Emit("message:send", args);

        }
    }
}

f:id:take4kamada:20140711160943p:plain

追記

やっぱりこっちを使ったほうがよさげ
https://github.com/kaistseo/UnitySocketIO-WebSocketSharp https://github.com/KLab/websocket-unitymobile

NginxによるWebSocketの負荷分散

Node.js、Socket.IOを使ってリアルタイムなWebアプリなんかを作っていて、分散構成はどうすればいいのか試行錯誤しているメモ。

Nginxは1.3.13からWebSocketのプロキシに対応したので以下を参考にサクッとやってみる。 http://nginx.org/en/docs/http/websocket.html

upstream chatserver {
    server xxx.xxx.xxx.xxx:3000;
    server yyy.yyy.yyy.yyy:3000;
}

server {
    listen       3000;
    server_name  localhost;

    location / {
        proxy_pass http://chatserver;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

この設定でも確かにプロキシされたし、分散もされた。
しかし、接続先のサーバーが頻繁に変わってしまうようで、アプリの挙動がおかしくなった。

なのでセッションごとに同じサーバーに接続する仕組みが必要。
ip_hashだとなんとなくサーバーが偏りそうな気がしたのでstickyを試す。

http://nginx.org/en/docs/http/ngx_http_upstream_module.html
ここを見ているとstickyが標準で入っているっぽいが、実際には入っていないのでNginxをビルドし直してサードパーティモジュールとして組み込む。
(Nginx Plusなら入ってるのかな?)

stickyのダウンロード先、ビルド方法は以下を参照。
https://bitbucket.org/nginx-goodies/nginx-sticky-module-ng

設定はほとんど変わらず、stickyを追記するだけ。

upstream chatserver {
    sticky;
    server xxx.xxx.xxx.xxx:3000;
    server yyy.yyy.yyy.yyy:3000;
}

今のところこれでいけそう。
ちなみに各バージョンは

Nginx : 1.6.0
Node.js : v0.10.28
Socket.IO : 0.9.17

Nodeを分散するとNodeプロセス間でのデータの共有が必要で、それにはRedisのPub/Subがよいらしい。

http://www.cyberagent.co.jp/recruit/techreport/report/id=8858#id-2013-09%E6%8F%90%E5%87%BA%E5%88%86%EF%BC%8F%E5%85%AC%E9%96%8B%E7%94%A8%EF%BC%8F%E3%82%AA%E3%83%B3%E3%83%A9%E3%82%A4%E3%83%B3%E9%80%9A%E7%9F%A5%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0-homing-%EF%BC%88%E5%8F%A4%E8%B0%B7%E8%96%AB%EF%BC%89-2-4.Redis%E3%82%B5%E3%83%BC%E3%83%90%EF%BC%88Socket.IO%E7%94%A8%EF%BC%89

以上、アリーヴェデルチ

sentinel利用時の注意点

ipの変更があった時にsentinel.confのsentinel monitorで新しいmasterのipを指定して再起動したが、勝手にslaveに変えられてしまってハマった。

sentinelはfailover時、以下のように情報をsentinel.confに追記する。

# Generated by CONFIG REWRITE
dir "/hoge/fuga"
sentinel known-slave mymaster xxx.xxx.xxx.xxx 6379
sentinel known-sentinel mymaster yyy.yyy.yyy.yyy 26379 e80c02f0a7899dcb69f01ff5050a88ded04c6f6c
sentinel current-epoch N

これが残っていると古いipを元にレプリケーションしてしまう。
dump.rdbも容赦なく上書きされた。。定期的にバックアップ取るべきだった。。

なので残っていないか要チェック。ec2インスタンスタイプ変更などで陥るかも。
ちゃんとSentinel commandsも覚えるべきかな。。

参考
http://d.hatena.ne.jp/rx7/20140410/p1
http://redis.io/topics/sentinel