2014/07/17

[Swift, iOS]playgroundでUIKit(UIButtonなど)を使用する方法

playgroundを使用していて、なんでUIButtonを宣言できないんだ?
と思ったので調べました。

1)playground を起動し、 「File Inspector」を表示する

Xcodeのメニューから「Show File Inspector」を選択し、「File Inspector」表示します。



2)Platformを「iOS」に変更する

[Playground Settings] → [Platform] を「OS X」から「iOS」に変更します。



3)「UIKit」を import に追加する

import に「UIKit」を追加し、既存の「import Cocoa」を削除します。



以上で準備は完了です。
 では、UIButton を定義してみましょう。



結果もすぐに確認できてとても便利ですね〜。

-----
Xcode 6 Beta 3 は無料でDLできるようになりました(Apple Blog)。
皆さんどんどん遊んでみましょう。


2014/06/29

[Swift, iOS]Swiftのmapとreduceについて書いてみた


Swiftについて勉強していく中で一番興味引かれたキーワードが「関数型言語」でした。
中でも以下のサイトを拝見させていただいたことで一気に関数型言語の理解が進みました!!
この場を借りて感謝を述べさせていただきます。

 ・Swiftで脱アルゴリズム!iOS開発を関数型(宣言型)プログラミングへパラダイムシフトしてみる【脱アルゴリズム宣言①】

(追記 22:26)
Swiftは関数型言語ではないという記事を見つけました。
 ・Swift Is Not Functional

mapとreduceについて

関数型言語と命令型プログラミング言語について語る上で、よく引き合いに出されるメソッドのようです。
この2つのメソッドを利用することで for文 や if文 を記述する回数を減らし、バグの少ないコードが書けます(理由は上記のサイトをどうぞ)。

Swiftでもmap, reduceが使える

Swiftでもmap, reduceが使えます!

let arry = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

// map
let mapRet = arry.map{
    
    (var n) -> Int in
    
    return n + 2;

}
mapRet        // [2, 3, 4, 5, 6, 7, 8 ,9, 10, 11, 12]


// reduce1
println("reduceRet1")
let num = 0;       
let reduceRet1 = arry.reduce(num){     // |num| は |m| の初期値
    
    (var m, var n) -> Int in
    
    println("m = \(m), n = \(n)")
    
    return m + n    // return値が次の|m|の値となる
}
reduceRet1      // 55

mapについては特に説明不要でしょう。配列のすべての値に対して 2 を足しています。
reduceで注目すべきは num です。ここでは num の値を 0 としていますが、値を変更することで、 m の初期値を変更する事ができます。
m, nの具体的な値の変化は以下です。


非常に便利&完結にコードを書けますね。Swiftで開発するときは積極的に利用していくべきでしょう。

(おまけ)無名関数の書き方

以下のように色々な書き方ができるようです。
開発時はチーム内で統一した方がよさそうですね。

// reduce2
// return 削除
let reduceRet2 = arry.reduce(num){
    
    (var n, var m) -> Int in n + m
}

// reduce3
// さらに戻り値の型 削除
let reduceRet3 = arry.reduce(num){
    
    (var n, var m) in n + m
}

// reduce4
// $ のみで書く。変数 |n|, |m| の変わりです。
let reduceRet4 = arry.reduce(num){ $0 + $1 }




2014/06/04

[Xcode, Git]Xcode 5 のGitでDropboxをリモートリポジトリとして使用する方法

色々あって作業&ブログ更新が思ったよりできていません。なんとか夏までにはどのような形でも良いのでアプリをリリースすることを目標に作業しなくちゃ。

さて今回は、Xcode 5のGitでDropboxをリモートリポジトリとして使用できるようにする方法を紹介します。
試した環境はこちら↓

  ・OS X 10.9.3
  ・Xcode 5.1.1
  ・Mac OS版 Dropboxクライアントが必要
  ・Mac OS用 Gitクライアント


Step1:ローカルリポジトリの作成 〜 コミット


1)新規プロジェクトの作成
  Source Controlにチェックし、ローカルリポジトリを作成します。

  余談ですが、プロジェクトの途中からリポジトリ管理を追加するのはとても
  手間がかかるようです。
  



2)ソースの編集
  まずはソースを編集してビルドしてみましょう。するとソース名の右側に「M」(Modify:修正)が付きます。


3)ソースの追加
  次にソースを追加すると、ソース名の右側に「A」(Add:追加)が付きます。


4)ローカルリポジトリへのコミット
  [メニュー] → [Source Control] → [Commit...] を選択することで、変更のあったファイルがすべて一覧表示されます。
  また各ソースを選択することで、ソースのどの箇所に変更があったかを表示してくれます。
  変更箇所を確認し、コメントを記入後コミットします。
  (コメントは日時、変更者、要点などフォーマットを決めておくとよいでしょう)



5)コミットの完了
  コミットが完了すると「M」、「A」などのマークが消えます。



Step2:Dropbox上でのリモートリポジトリの作成 〜 Push


Dropbox上にリモートリポジトリを作成します。
あらかじめ「Mac OS版 Dropboxクライアント」と「git」をインストールしておいてください。


1)フォルダの作成
  Dropbox上にフォルダを作成します。ここでは「GitTest2」という名前にしています。
  Xcodeにこのフォルダの絶対パスを設定するのでメモしておいてくださいね。


2)フォルダの初期化
  1)で作成したフォルダを、ターミナルから以下のコマンドを使用して初期化します。

  $git --bare init


  初期化に成功すると以下のようにリポジトリ管理用のファイルが作成されます。


3)Xcodeへリモートリポジトリの設定
  [Xcode] → [Source Control] → [フォルダ名称] → [Configure フォルダ名称] を選択して、
  リモートリポジトリを設定するダイアログを表示します。


[Remotes] → [+] を選択。




  以下の2つを入力します。
    Name:識別しやすい名前
    Address:Dropbox上に作成したフォルダのフルパスを指定


  リモートリポジトリが正常に追加されました。


4)リモートリポジトリへのPush
  設定が無事完了したら、早速リモートリポジトリへPushしてみましょう!  
  [Source Control] → [Push...] を選択してダイアログを表示します。


  3で作成したリポジトリを選択します。
  「Repository is online」と表示されていれば、正常にPushできます。
  成功すると「successful」と表示されます。


5)Dropbox上でPushが成功したか確認
  以下のファイルの更新日時がPushした時間になっていれば、成功です。
  

Step3:リモートリポジトリからのCheck Out


Step2で作成したDropbox上のリモートリポジトリから、プロジェクト一式を取得します。

1)Welcom to Xcode を表示します。


  [Check out an existing project]を選択します。


2)Dropbox上のフォルダの絶対パスを入力
  Step2の1で作成したフォルダの絶対パスを入力します。



3)プロジェクト一式の配置場所を指定します。




4)Check Out に成功するとプロジェクトが立ち上がります

























以上で作業は完了です。
おつかれさまでしたー。

WWDCでiOS8やSwiftが発表されましたね。
これからも忙しくなりそうです :-)

2014/05/05

Bloggerでブログやサイドバーの幅を変更する方法

サイドバーのサイズ変更の方法について紹介します。
 ※選択しているテンプレートによっては、変更方法が異なると思います。

まずは、[テンプレート] → [HTMLの編集] をクリック。

以下の行を編集します。

 


 
 
 
 
左のサイドバーは表示していないので、「0」になっています。ブログ本文の方には、"value"属性があるのでそちらを変更します。
ターゲットとしている方のPCの幅などを考慮して値を変更しましょう。

2014/04/05

[iOS]カメラ勉強備忘録 - その2(CIDetector のメモリリーク)

こんばんわ!
あまりブログを書けてませんが、粛々と勉強中です。

CIDetector を使用して顔認識までは無事出来ました。
が、CIDetector のメモリリークにはまったのでメモ。
( iOS7.1 SDK を使用 )

captureOutput:didOutputSampleBuffer:fromConnection: メソッドで
取得したすべてのカメラ画像に対して顔認識しています。
その際、CIDetector は生成する際のコストが高いため使い回わしていましたが、
これがまずかった。

static CIDetector *detector = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    detector = [CIDetector detectorOfType:CIDetectorTypeFace
                                  context:nil
                                  options:@{CIDetectorAccuracy: CIDetectorAccuracyLow}];
});
    
NSDictionary *options = @{
                          CIDetectorSmile: @(YES),
                          CIDetectorEyeBlink: @(YES),
                          };
    
NSArray *features = [detector featuresInImage:ciImage options:options];


同一の CIDetector インスタンスに対して featuresInImage: メソッドの実行を
繰り返すと、毎回メモリリーク( CIDetector のバグ?)していき、
最終的にはアプリが強制終了した。

回避方法としては、CIDetector インスタンスを毎回生成するように修正する。

 CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeFace
                                           context:nil
                                           options:@{CIDetectorAccuracy: CIDetectorAccuracyLow}];
        
 NSDictionary *options = @{
                           CIDetectorSmile: @(YES),
                           CIDetectorEyeBlink: @(YES),
                           };
        
 NSArray *features = [detector featuresInImage:ciImage options:options];

これで、OK!
性能は悪くなるが、仕方なしとしよう。

2014/03/08

[iOS]iOS Developer Programへの登録方法


iOSアプリを実機で動作確認したり、アプリをApp Storeで公開するためには、iOS Developer Programに登録(参加)する必要があります。

今回、その登録方法をスクリーンショット付きでメモしました。
登録には1〜2日かかる(Activationのメール待ち)ので、時間に余裕持って作業ましょう。
 ※2014/03/02 時点での情報となります。
 ※支払いには「クレジットカード」または、「Apple Storeギフトカード」が
  必要となります。

なお、私は既にApple ID 取得済みでしたので、その手順は省略しています。

1.iOS Developer Program のサイトにアクセスします。


2.「今すぐ登録」を押下します。


3.「続ける」を押下します。


4.今回は、Apple IDは作成済みなので「Sign In」を押下します。



5.「Apple ID」と「Password」を入力して「Sign In」します。



6.「Individual(個人)」を選択します。



7.「クレジットカードの情報」、「存在する住所」を入力します。
  この時、氏名、住所などに全角文字(漢字やひらがな)を使用せず、
  ローマ字で入力した方がよいです(文字化けします)。



8.[iOS Developer Program] にチェックして、[Continue]を押下します。




9.「iOS Developer Programの金額」、「入力した情報」を確認して
   [Continue] を押下。

  氏名などが文字化けしているのは、漢字などの全角文字を使用して
  しまったせいです ^^;
  


10.ライセンスに目を通し、同意したことを表すチェックをし、
[I Agree]を押下します。


11.「Buy Now」を押下します。



12.もう一度ログインします。



13.支払いに必要な情報を入力します。
今回はクレジットカードで支払いをしました。


14.入力した情報、金額を確認し、「ご注文の確定」を押下します。



15.購入が完了しましたので、あらためて、iOS Developer Centerへ
ログインします。


16.ログインして、[View Details]を押下すると、以下の画面のように

  「Contacting Your Reference」と表示されている画面が表示されます。
   ※どうやら私が入力した情報について、Appleが本人確認をしているようです。
    この本人確認プロセスが1〜2日かかるようで、完了するとiOS Developer 
    Program の年間契約が開始となります。

   私はここでよくわからずに「Contact Us」から問い合わせしてしまいましたが、
   質問の回答が来る前にプロセス完了のメールが来ました。
   

17.本人確認プロセスが完了すると、Appleから以下のメール2通(英語、日本語)が

   来ました(私はこのメールが来るまで2日ほどかかりました)。
   このメールの受信日から1年間が契約期間になります。














18.あらためて iOS Developer Center にログインすると、

   以下の画面のようなメニューが表示されていて、証明書などの
   作成ができるようになっています。


iOS Developer Program への登録が無事完了しました。

iOSアプリ開発をみんなで楽しみましょうー!!


2014/02/23

[小ワザ] Bloggerにキレイにソースコードを表示する方法


Bloggerでソースコードをキレイに表示する方法でハマったのでメモ。

1.以下のサイトを参考にSyntaxHighlighterをダウンロードします。



2.ダウンロードしたファイルの配置


 Bloggerにファイルをアップロードできればよいのですが、
 できないみたいなので、DropboxのPublicフォルダで代用します。

 Publicフォルダに配置することで外部からファイルを参照できるようになります。
 ファイルを配置後「公開リンクをコピー」でURLを取得し、「src=」に指定すればOK。
    
 


気になるページの表示にかかる時間ですが、せいぜいファイル数が4つなので体感できるほどではないかと。
問題があるようだったら別の方法を考えます。

2014/01/27

[iOS]カメラ勉強備忘録 - その1



iOSのプログラミングについて備忘録的に書いていこうと思います。

最終的には、AVFoundation を使用してリアルタイム顔認識したいです。

まずは、CoreImageを使ってフィルターの勉強をするために
以下のサイトを参考にさせていただきました。

・iPhoneカメラアプリ開発入門(第一回)

実装方法の詳細は上記サイトの通りなので、
CIFilterを作成する際にちょっと一工夫。

/** 画像に指定されたフィルタを適用する */
+ (UIImage *)adhibitionFilter:(UIImage *)image withFilter:(TImageFilters)type
{
    if (type == TImageFilterNone) {
        return image;
    }
    
    // CoreImageFilterを作成する
    CIFilter *filter = [[self class] createFilterWithType:type intensity:1.0f targetImage:image];
    
    // coreimageコンテクストを作成
    CIContext *ciContext = [CIContext contextWithOptions:nil];
    
    // フィルタを適用
    CGImageRef cgImage = [ciContext createCGImage:filter.outputImage fromRect:[filter.outputImage extent]];
    
    // UIImageに変換
    UIImage *retImage = [UIImage imageWithCGImage:cgImage scale:image.scale orientation:UIImageOrientationUp];
    
    CGImageRelease(cgImage);
    
    return retImage;
    
}

/** フィルターを生成する */
+ (CIFilter *)createFilterWithType:(TImageFilters)type
                         intensity:(CGFloat)intensity
                       targetImage:(UIImage *)image
{
    CIImage *ciImage = [[CIImage alloc] initWithImage:image];

    // CoreImageFilterを作成する
    CIFilter *filter = [CIFilter filterWithName:[[self class] createFilterNameWithType:type]];
    
    [filter setValue:ciImage forKey:kCIInputImageKey];

    /** ### */
    /** パラメータを動的に生成して、どんなフィルタ名にも対応できるようにしています */
    /** ### */
    NSDictionary *params = [[self class] createFilterParametarWithType:type];
    NSArray *keys = [params allKeys];
    for (NSString *key in keys) {
        /** フィルタに存在しないパラメータの場合は設定しない */
        if ([filter respondsToSelector:NSSelectorFromString(key)] == NO) {
            continue;
        }
        
        [filter setValue:[params objectForKey:key] forKey:key];
    }
    
    return filter;
}

/** フィルタータイプにあったフィルタ名を生成する */
+ (NSString *)createFilterNameWithType:(TImageFilters)type
{
    
    NSString *name = nil;
    
    switch (type) {
        case TImageFilterMonochrome:
        case TImageFilterMonoSepia:
            name = kFilterNameMonochrome;
            break;
            
        case TImageFilterSepiaTone:
            name = kFilterNameSepiaTone;
            break;
            
        case TImageFilterNone:
        default:
            name = nil;
            break;
    }
    
    return name;
}

/** フィルタータイプにあったパラメータを生成する */
+ (NSDictionary *)createFilterParametarWithType:(TImageFilters)type
{
    
    NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
    
    // CIFilterに指定するパラメータ名
    NSString * const keyInputColor     = @"inputColor";
    NSString * const keyInputIntensity = @"inputIntensity";
    
    switch (type) {
        case TImageFilterMonochrome:
        case TImageFilterMonoSepia:
            
            // パラメータ:入力色(RGBのフィルタ係数)
            [params setObject:[[self class] createCIColorWithType:type] forKey:keyInputColor];
            // パラメータ:適用度 (0.5で半分になる)
            [params setObject:[NSNumber numberWithFloat:1.0f] forKey:keyInputIntensity];
            
            break;
            
        case TImageFilterSepiaTone:
            // パラメータ:適用度 (0.5で半分になる)
            [params setObject:[NSNumber numberWithFloat:1.0f] forKey:keyInputIntensity];
            break;
            
        case TImageFilterNone:
        default:

            break;
    }
    
    return params;
}

実行結果は以下のとおりです。
UIPickerView を使ってフィルターを動的に選択できるようにしています。

 ・フィルター無し

 ・モノクロ

 ・セピア(CIColorMonochromeフィルタ)

・セピア(CISepiaToneフィルタ)

次回は、AVFoundation についての勉強か iOS Dev Program に登録します。