nirasan's tech blog

趣味や仕事の覚え書きです。Linux, Perl, PHP, Ruby, Javascript, Android, Cocos2d-x, Unity などに興味があります。

NGUI の ScrollView で気持ちのいいスクロールを実装する

気持ちが良いスクロールとは?

  • 今回は「ちょっとスワイプするだけで次の要素にスッと切り替わる」ものを実装する。

バージョン情報

  • Unity 4.6.1f
  • NGUI 3.7.6

ヒエラルキー

UI Root
	ScrollView
		Grid

ScrollView の作成

  • メニューの [NGUI] > [Create] > [Scroll View] で作成

Grid の作成

  • メニューの [NGUI] > [Create] > [Grid] で作成
  • UICenterOnChild をアタッチ

オプション設定

  • UIGrid の Sorting を None 以外にする
    • わからなければ Custom にする
  • UICenterOnChild の NextPageThreshold を 1 にする

動作確認

  • Grid 配下に任意の UIDragScrollView とコライダーがアタッチされたオブジェクトを追加して動作を確認する。

解説

  • UICenterOnChild.NextPageThreshold が 0 より大きく、UIGrid の Sorting が None 以外である時、スワイプした距離が NextPageThreshold より大きければ UICenterOnChild により次あるいは前の要素に切り替わる。

注意点

  • ScrollView をループさせるスクリプトの UIWrapContent が有効であると、この処理は正常に行われなかった。

Rails 4.2 で Heroku にデプロイしたメモ

はじめに

  • Rails 4.2 で開発していたアプリを Heroku にデプロイした時にやったことメモ

環境

Heroku にユーザー登録

Heroku アプリの作成

$ cd /path/to/rails/app
$ heroku create

Heroku 用の gem の追加

$ vi Gemfile
-gem 'sqlite3'
+gem 'sqlite3', :group => [:development, :test]
+gem 'pg', :group => [:production] # heroku で DBMS として PostgreSQL を使用するために必要
+gem 'rails_12factor', group: :production # heroku で Rails 4 を動かすために調整してくれるやつ
$ bundle install --without production

Devise の設定

  • Devise を使っている場合
$ vi config/initializers/devise.rb
config.secret_key = '<%= ENV["DEVISE_SECRET_KEY"] %>' if Rails.env.production? 
heroku config:add DEVISE_SECRET_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

データベースの設定

$ vi config/database.yml
production:
  adapter: postgresql
  encoding: unicode
  pool: 5

シークレットキーの設定

  • シークレットキーを環境変数から読み込むように
$ vi config/secrets.yml
  secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>                                                                                                                                    
  • .gitignore に config/secrets.yml が登録されている場合は削除する

デプロイ

$ git commit -am 'for heroku'
$ git push heroku master
$ heroku run rake db:migrate

Rails 4.2 で destroy のバリデーションをする

任意の条件でバリデーションをする

  • http://qiita.com/tbaba/items/9ea139dc77443e6d7be2 の通り、before_destroy に指定したメソッド内で条件を判定し、destroy 不可であれば return false する
  • 前記記事の通り before_destroy :method_name の記法ではなく、before_destroy do ... end で宣言すると、return false 時に LocalJumpError の例外が発生して意図したように動作しなくてはまった

関連レコードがある場合は destroy できないように

  • バリデーションの条件として、関連するレコードがあったら destroy 出来なくしたいだけの場合は has_meny のオプションだけで対応できる
models
has_many :associate_name, dependent: :restrict_with_error
# has_many のその他のオプション
# http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many
controllers
if @result = @obj.destroy
  # 成功
else
  # 失敗
end

Unity Ads 導入メモ

やったこと

  • Unity Ads のサイトにアカウント登録
  • Unity Ads でアプリの登録とID取得
  • Asset Store から Unity Ads のインポート
  • 広告の呼び出しスクリプトの作成と実行

スクリプト

AdsManager
using UnityEngine;
using System.Collections;
using UnityEngine.Advertisements;

public class AdsManager : MonoBehaviour {

	void Awake() {
		if (Advertisement.isSupported) {
			Advertisement.allowPrecache = true;
			Advertisement.Initialize (Config.unityAdsId, true);

		} else {
			Debug.Log("Platform not supported");
		}
	}

	public void Show() {
		Advertisement.Show(null, new ShowOptions {
			pause = true,
			resultCallback = result => {
				Debug.Log("広告閲覧終了。広告閲覧報酬を付与するならここで。");
				Debug.Log(result.ToString());
			}
		});
	}
}
Config
using UnityEngine;
using System.Collections;

public class Config {

	#if UNITY_IPHONE
	public static string unityAdsId = "iOSアプリのID";
	#elif UNITY_ANDROID
	public static string unityAdsId = "AndroidアプリのID";
	#endif
}
広告表示
	GameObject.FindObjectOfType<AdsManager>().Show();

MagicalRecord で Date の範囲検索

  • Entity エンティティの creationDate 属性に作成日時が入っているものとして、今日作成されたデータを取得する場合
// 今日の0時0分0秒を取得
NSCalendar* calendar = [NSCalendar currentCalendar];
unsigned int flags = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay;
NSDateComponents* components = [calendar components:flags fromDate:[NSDate date]];
NSDate* fromDate = [calendar dateFromComponents:components];

// 明日の0時0分0秒
NSDate* toDate = [fromDate dateByAddingTimeInterval:60*60*24];

// 検索条件の作成と実行
NSPredicate* p = [NSPredicate predicateWithFormat:@"(creationDate >= %@) AND (creationDate < %@)", fromDate, toDate];
Entity* entity = [Entity MR_findFirstWithPredicate:p];

MagicalRecord を試したメモ

はじめに

  • iOS アプリ開発で ActiveRecord ライクに CoreData を扱うことが出来る MagicalRecord を試したメモ
  • CocoaPod を使うのも初めてなのでそこもちょっと詳しく

動作環境

  • XCode 6.1.1
  • MagicalRecord 2.2
  • mogenerator 1.27

CoreDateの用語

  • 管理オブジェクト(NSManagedObject) : レコード
  • 管理オブジェクトコンテキスト(NSManagedObjectContext) : ORM
  • 管理オブジェクトモデル(NSManagedObjectModel) : スキーマ

プロジェクトの作成

  • "Use Core Data" にチェックを入れて作成

MagicalRecord のインストール

CocoaPod のインストール

  • インストールしていなければ
sudo gem install cocoapods

MagicalRecord のインストール

# cd /path/to/xcode/project
# /usr/bin/pod init
# vi Podfile
target 'ProjectName' do
  pod "MagicalRecord"
  pod "MagicalRecord/Shorthand"
end
# /usr/bin/pod update

MagicalRecord を読み込む

  • pod update によって CocoaPods が有効な状態の XCode プロジェクトファイル(APPNAME.xcworkspace)が生成されているので、これを開く
# open App.xcworkspace
  • CocoaPods のビルドを行う
    • 画面左上の方にあるビルド対象のセレクトボックスをクリックして "New Scheme" を選択
    • "Pods-APPNAME" を選択してビルド対象として作成
    • ビルドデバイスを "iOS Device" に変更し、ビルドを実行

エンティティ(テーブル)の追加

  • APPNAME.xcdatamodeld ファイルを選択
  • "Add Entity" ボタンでエンティティの作成
  • 画面右のインスペクタで Entity の Name と Class を設定 (Class はクラスファイル生成時に必要)
  • エンティティを選択して "Add Attribute" ボタンでアトリビュート(カラム)の作成

リレーションシップについて

  • http://qiita.com/yuiseki/items/33ec35ec99b5304be90a
  • Auther エンティティと Book エンティティが 1:多 の関係になるとする
  • Auther の設定
    • Auther の Relationships で "+" を押下しリレーションシップを作成
      • Relationships を books
      • Destination を Book
      • Inverse はとりあえずそのまま(Book 側の Inverse を設定すれば自動でセットされる)
    • Auther の books を選択した状態のインスペクタで、Relationships の Type を "To Many" に
    • 同じく "Delete Rule" を "Cascade" にすると Auther 削除時に関連する Book も削除されるので任意で設定
  • Book の設定
    • Book の Relationships で "+" を押下しリレーションシップを作成
      • Relationships を auther
      • Destination を Auther
      • Inverse は books
    • Book の auther を選択した状態のインスペクタで、Relationships の Type を "To One" に

カスタム管理オブジェクトクラスの作成

mogenerator のインストール

# brew install mogenerator
# /usr/local/bin/mogenerator -v

ファイルの作成

# /usr/local/bin/mogenerator -m Model.xcdatamodeld/Model.xcdatamodel -O CoreData/ --template-var arc=true

MagicalRecord の初期化

AppDelegate.h

#import <MagicalRecord.h>
#import <MagicalRecord+Setup.h>

AppDelegate.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [MagicalRecord setupCoreDataStackWithAutoMigratingSqliteStoreNamed:@"app.db"]; // 追記
    return YES;
}
- (void)applicationWillTerminate:(UIApplication *)application {
    [MagicalRecord cleanUp]; // 追記
}

MagicalRecord を使う

ViewController.h

  • Auther.h, Book.h はカスタム管理オブジェクトクラス
#import <CoreData/CoreData.h>
#import <CoreData+MagicalRecord.h>
#import "Auther.h"
#import "Book.h"

ViewController.m

- (void)viewDidLoad {
    [super viewDidLoad];
    
	// Auther の作成
    Auther* auther = [Auther MR_createEntity];
    auther.name = @"Neal Stephenson";
    
	// Book の作成と Auther との関連付け
    Book* book1 = [Book MR_createEntity];
    book1.title = @"Snow Crash";
    [auther addBooksObject:book1];

    Book* book2 = [Book MR_createEntity];
    book2.title = @"The Diamond Age";
    [auther addBooksObject:book2];

    Book* book3 = [Book MR_createEntity];
    book3.title = @"Cryptonomicon";
    [auther addBooksObject:book3];
	
	// 作成したレコードの登録
    [[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreAndWait];
    
	// Auther の一覧を取得
    NSArray* array = [Auther MR_findAll];
    int i = 0;
    NSLog(@"Count:%lu", (unsigned long)[array count]);
    for (Auther* a in array) {
        NSLog(@"#####%d name=%@", i, a.name);
		// Auther に関連付いた Book の取得
        for (Book* b in a.books) {
            NSLog(@"----- title=%@", b.title);
        }
        i++;
    }
	
	// 削除
	[auther MR_deleteEntity];
    [[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreAndWait];
}