2013年12月28日土曜日

iOSで詳細ビューを追加する


前回作成したテーブルビューから遷移する詳細ビューを追加する。
詳細ビューとして、ストーリーボードにView Controller(紐づけるクラス名はDetailViewControllerとする)を追加する。

Table View Controller(クラス名:ViewController)からView Controller(クラス名:DetailViewController)へのセグエを設定する。
Storyboard Segue: 「identifier」に"getDetail"と入力、「Style」に"push"を選択する。


Table View Controller(クラス名:ViewController)のバックボタン表示名を変更する
Navigation Item: 「Back Button」に"プロ野球"と入力する。


詳細ビュー(クラス名:DetailViewController)をコーディングする。
#import <UIKit/UIKit.h>

@interface DetailViewController : UIViewController

@property (weak, nonatomic) IBOutlet UILabel *detailLabel;
@property (strong, nonatomic) NSString *detailItem;

@end
#import "DetailViewController.h"

@implementation DetailViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.detailLabel.text = self.detailItem;
    NSLog(@"self.detailItem is %@", self.detailItem);
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}

@end


テーブルビュー(クラス名:ViewController)をコーディングする。
ViewController.mにおいてDetailViewController.hをインポートし、prepareForSegue: sender:メソッドを追加する。
#import "ViewController.h"
#import "DetailViewController.h"

@interface ViewController ()

@end

@implementation ViewController {
    @private
    NSArray *_leagueKinds;
    NSArray *_leagues;
    NSArray *_leaguePrefixes;
}

#pragma mark - Navigation

// In a story board-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
    if ([[segue identifier] isEqualToString:@"getDetail"]) {

        NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
        NSArray *teams = _leagues[indexPath.section];
        NSArray *teamPrefixes = _leaguePrefixes[indexPath.section];
        
        [[segue destinationViewController] setTitle:teams[indexPath.row]];
        [[segue destinationViewController] setDetailItem:teamPrefixes[indexPath.row]];
    }   
}
@end

2013年12月23日月曜日

iOSでテーブルビューを使う


環境
  • Xcode 5.0.2
  • ARC ON
  • iOSシミュレータ 7.0

ストーリーボードにNavigation ControllerとTable View Controllerを追加する。

Table View Cell: 「Style」から"Subtitle"を選択、「Identifier」に"Cell"と入力する。

この紐付けをしておかないと実行時に下記エラーが吐かれる。
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'unable to dequeue a cell with identifier Cell - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'


Navigation Item: 「Title」に"日本プロ野球チーム"と入力する。


UITableViewControllerを継承したクラス(今回の例ではViewController)を作成する。

tableView: cellForRowAtIndexPath:メソッドとtableView: viewForHeaderInSection:メソッドはテーブルビュー初回描画時と画面スクロールが発生するたびに呼ばれる。
#import <UIKit/UIKit.h>

@interface ViewController : UITableViewController

@end
#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController {
    @private
    NSArray *_leagueKinds;
    NSArray *_leagues;
    NSArray *_leaguePrefixes;
}

- (id)initWithStyle:(UITableViewStyle)style
{
    self = [super initWithStyle:style];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Uncomment the following line to preserve selection between presentations.
    // self.clearsSelectionOnViewWillAppear = NO;
 
    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem;
    
    _leagueKinds = @[@"セントラル・リーグ", @"パシフィック・リーグ"];
    
    _leagues = @[
                @[@"ジャイアンツ", @"タイガース", @"ドラゴンズ", @"ベイスターズ", @"カープ", @"スワローズ"],
                @[@"バッファローズ", @"ホークス", @"ファイターズ", @"マリーンズ", @"ライオンズ", @"ゴールデンイーグルス"]
                ];
    
    _leaguePrefixes = @[
                       @[@"読売", @"阪神", @"中日", @"横浜DeNA", @"広島東洋", @"東京ヤクルト"],
                       @[@"オリックス", @"福岡ソフトバンク", @"北海道日本ハム", @"千葉ロッテ", @"埼玉西武", @"東北楽天"]
                       ];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    // Return the number of sections.
    return [_leagueKinds count];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // Return the number of rows in the section.
    return [_leagues[section] count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

//    if (!cell) {
//        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
//    }
 
    NSArray *teams = _leagues[indexPath.section];
    NSArray *teamPrefixes = _leaguePrefixes[indexPath.section];
    cell.textLabel.text = teams[indexPath.row];
    cell.detailTextLabel.text = teamPrefixes[indexPath.row];
    
    return cell;
}

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    static NSString *HeaderIdentifier = @"Header";
    UITableViewHeaderFooterView *view = [tableView dequeueReusableHeaderFooterViewWithIdentifier:HeaderIdentifier];
    
    if (!view) {
        view = [[UITableViewHeaderFooterView alloc] initWithReuseIdentifier:HeaderIdentifier];
    }
    
    view.textLabel.text = _leagueNames[section];

    return view;
}

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return 40;
}

@end

2013年11月13日水曜日

gitリポジトリを引っ越す

mirrorオプションをつけて実行する。
$ git clone --mirror git@before.example.com:hogeuser/Sample.git
$ cd Sample.git
$ git push --mirror git@after.example.net:foouser/Sample.git

[参考URL]
What's the difference between git clone --mirror and git clone --bare

2013年10月28日月曜日

Homebrewをアンインストールする

デフォルト設定で使っている場合は、下記を実行してHomebrewをアンインストールする。
$ brew doctor
$ brew update
$ git clone https://gist.github.com/1173223.git
$ cd 1173223/
$ chmod u+x uninstall_homebrew.sh
$ sh ./uninstall_homebrew.sh

必要に応じて、さらに下記を実行する。
$ rm -rf /usr/local/Cellar /usr/local/.git && brew cleanup

[参考URL]
How do I uninstall Homebrew?

2013年9月9日月曜日

Node.jsバージョン管理ツールを導入する(Windows編)

Windowsで利用可能なNode.jsバージョン管理ツールは複数あるが、ここでは個人的に最も使い勝手の良いと思われるnodistの導入方法について説明する。

プロキシ環境下にある場合は過去の内容を参考にプロキシ設定する。
$ git config --global http.proxy http://proxy.example.com:8080
$ git config --global https.proxy http://proxy.example.com:8080
$ git config --global url."https://".insteadOf git://

nodistをインストールする。
$ git clone git://github.com/marcelklehr/nodist.git

PATHを通すために、下記の通りシステム環境変数をセットする(下記は該当箇所のみ抜粋)。
変数
Path %HOMEDRIVE%%HOMEPATH%\nodist\bin

64bit環境の場合は下記の通りシステム環境変数をセットする。
変数
NODIST_X64 1

プロキシ環境下にある場合は下記の通りシステム環境変数をセットする。なお、nodist内部でHTTPS_PROXYはHTTP_PROXYに置換されるようなので、現状、HTTPS_PROXYについては設定しなくても問題ないと思われる。
変数
HTTP_PROXY http://proxy.example.com:8080
HTTPS_PROXY http://proxy.example.com:8080

nodist依存関係ファイルをインストールする。
> nodist update

動作確認する。
> nodist -v
0.3.8

Node.jsの最新安定版をインストールしてみる。
> nodist dist
> nodist stable
0.10.18

使用するNode.jsのバージョンを指定する。
> nodist 0.10.18
> node -v
v0.10.18

Node.jsバージョン管理ツールを導入する

OS Xで利用可能なNode.jsバージョン管理ツールは複数あるが、ここでは個人的に最も使い勝手の良いと思われるnodebrewの導入方法について説明する。

プロキシ環境下にある場合は下記の通りプロキシ設定する。
$ vim ~/.bashrc
$ source ~/.bashrc

~/.bashrc
# proxy
export http_proxy="http://proxy.example.com:8080"
export https_proxy="http://proxy.example.com:8080"

nodebrewをインストールする。
$ curl -L git.io/nodebrew | perl - setup

PATHを通す。
$ vim ~/.bashrc
$ source ~/.bashrc

~/.bashrc
# nodebrew
NODEBREW_ROOT=$HOME/.nodebrew
export NODBREW_ROOT
# PATH
PATH=$PATH:${NODEBREW_ROOT}/current/bin

動作確認する。
$ nodebrew -v
nodebrew 0.6.3

Node.jsの最新安定版をインストールしてみる。
$ nodebrew ls-remote
$ nodebrew install-binary stable
fetch: http://nodejs.org/dist/v0.10.18/node-v0.10.18-darwin-x64.tar.gz

使用するNode.jsのバージョンを指定する。
$ nodebrew use v0.10.18
$ node -v
v0.10.18


補足

私の環境では.bash_profileで.bashrcファイルを読み込むようにしている。

~/.bash_profile
source ~/.bashrc

2013年9月8日日曜日

Node.jsをアンインストールする(Windows編)

Windows用インストーラ(.msi)を使ってインストールしたNode.jsをアンインストールする。


はじめに削除すべきフォルダ、ファイル、環境変数を確認する。


フォルダ
%HOMEDRIVE%\Program Files\nodejs
%USERPROFILE%\AppData\Roaming\npm
%USERPROFILE%\AppData\Roaming\npm-cache

ファイル(プロキシ等を設定しているとき)
%HOMEDRIVE%%HOMEPATH%\.npmrc

ユーザー環境変数
変数
PATH %USERPROFILE%\AppData\Roaming\npm\

システム環境変数(該当箇所のみ抜粋)
変数
Path %HOMEDRIVE%\Program Files\nodejs\


実際に削除を行う。


"プログラムと機能"からnodejsアンインストーラを起動する。アンインストーラにより、%HOMEDRIVE%\Program Files\nodejsフォルダ、ユーザー環境変数、システム環境変数が削除される。

アンインストーラの削除対象となっていない下記フォルダを手動で削除する(プロキシ等を設定している場合は.npmrcファイルも要手動削除)。
%USERPROFILE%\AppData\Roaming\npm
%USERPROFILE%\AppData\Roaming\npm-cache

2013年9月7日土曜日

プロキシ環境下でgitを使う

プロキシの設定


下記の通りプロキシ設定する。
$ git config --global http.proxy http://proxy.example.com:8080
$ git config --global https.proxy http://proxy.example.com:8080

これで手動でhttpまたはhttpsスキームを指定したgit clone等ができるようになる。
$ git clone https://github.com/joyent/node.git

gitスキームのまま使いたい場合(通常はこのケースが多いだろう)は下記を追加設定する。
$ git config --global url."https://".insteadOf git://

これでgitスキームのままgit clone等ができるようになる。
$ git clone git://github.com/joyent/node.git


プロキシ設定の確認


gitコマンドによる確認
$ git config --list
(該当箇所のみ抜粋)
http.proxy=http://proxy.example.com:8080
https.proxy=http://proxy.example.com:8080
url.https://.insteadof=git://

.gitconfigファイルの確認
$ less ~/.gitconfig
(該当箇所のみ抜粋)
[http]
        proxy = http://proxy.example.com:8080
[https]
        proxy = http://proxy.example.com:8080
[url "https://"]
        insteadOf = git://


プロキシ指定についての補足

認証付きプロキシサーバの場合は認証ID、PW込みでプロキシ指定する。また、認証ID、PW、プロキシサーバURLにURIとして使用できない文字(@等)が含まれる場合はURLエンコードすること。

書式
$ git config --global http.proxy http://認証ID:認証PW@プロキシサーバのURL:ポート番号
$ git config --global https.proxy http://認証ID:認証PW@プロキシサーバのURL:ポート番号

設定例(認証IDがfoo.bar@example.com、認証PWがhogepassの場合)
$ git config --global http.proxy http://foo.bar%40example.com:hogepass@proxy.example.com:8080
$ git config --global https.proxy http://foo.bar%40example.com:hogepass@proxy.example.com:8080

2013年6月30日日曜日

WindowsストアアプリでTLS/SSL自己署名証明書を使う

Socket、HTTP、WebSocket通信はTLS/SSLを使って暗号化されることが多いが、Windowsストアプリでは証明書拡張機能を使ってアプリケーションと一緒にTLS/SSL証明書をインストールする方法が用意されている。
以下、WindowsストアアプリにおいてTLS/SSL自己証明書をインストールする方法について説明する。


1. 証明書を準備する


Windowsストアアプリでは通信接続先のサーバホスト名と証明書のCommon Nameが一致しているかチェックされるため、 前回の内容を参考に、Common NameについてFQDNまたはIPアドレスを正確に指定して自己署名証明書を作成する。
今回はserver-crt-192p168p1p101.pem(サーバIPアドレスが192.168.1.101)とserver-crt-192p168p1p102.pem(サーバIPアドレスが192.168.1.102)の2つのファイルを作成済みと仮定して進めていく。


2. アプリに証明書を配置する


準備した証明書ファイルをドラッグ&ドロップによりWindowsストアプリの適当な場所に配置する(下記例ではAssetディレクトリ以下に証明書ファイルを配置)。
各証明書ファイルのプロパティについて下記の通り設定する。
  • ビルドアクション: コンテンツ
  • 出力ディレクトリにコピー: 常にコピーする


3. マニフェスト宣言を行う

  1. サポートされる宣言について証明書を選択する。
  2. 各証明書について、ストア名にはRoot、コンテンツには該当証明書ファイル場所を入力する。
  3. 複数の証明書をアプリ側(アプリコンテナ)から自動選択させる場合は、自動選択にチェックを入れる。

Package.appxmanifestファイルに直接XML形式で記述する際は、Extensionsタグ内に記述する。
  </Capabilities>
  <Extensions>
  <!-- Certificates Extension START -->
    <Extension Category="windows.certificates">
      <Certificates>
        <Certificate StoreName="Root" Content="Assets\server-crt-192p168p1p101.pem" />
        <Certificate StoreName="Root" Content="Assets\server-crt-192p168p1p102.pem" />
        <SelectionCriteria AutoSelect="true" />
      </Certificates>
    </Extension>
  <!-- Certificates Extension END -->
  </Extensions>
</Package>

[参考URL]
How to connect to a Http Rest Service with Self Signed Certificate(in the server side).

2013年6月25日火曜日

TLS/SSL自己署名証明書を作成する

opensslコマンドを使ってTLS/SSLテスト用証明書を用意する。
非商用の場合はCAcert.org等から証明書を取得する方法もあるが、今回は内部テストでのみ利用するため、自己署名証明書(いわゆるオレオレ証明書)を作成することにする。


1. 秘密鍵を作成する。


作成する秘密鍵ファイル名をserver-key-192p168p1p101.pemとする。
$ openssl genrsa -out server-key-192p168p1p101.pem 2048


2. 証明書署名要求を作成する。


作成する証明書署名要求ファイル名をserver-csr-192p168p1p101.pemとする。
$ openssl req -new -key server-key-192p168p1p101.pem -out server-csr-192p168p1p101.pem

各種設定例は下記の通り。
Common Nameについては実際にTLS/SSLを使用するサーバのFQDNまたはIPアドレスを指定する事。
Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:Tokyo
Locality Name (eg, city) []:Shinagawa-ku
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Hoge Limited
Organizational Unit Name (eg, section) []:Piyo Unit
Common Name (e.g. server FQDN or YOUR name) []:192.168.1.101
Email Address []:foo@example.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:


3. 自己署名証明書を作成する。


作成する自己署名証明書ファイル名をserver-crt-192p168p1p101.pemとする。
$ openssl x509 -req -days 365 -in server-csr-192p168p1p101.pem -signkey server-key-192p168p1p101.pem -out server-crt-192p168p1p101.pem


[参考URL]SSL証明書インストールに関するメモ

2013年6月23日日曜日

iOSでHTTPリクエストする

比較的単純なHTTPリクエストを実行する際は、非同期リクエストであるNSURLConnectionクラスのsendAsynchronousRequest:queue:completionHandler:クラスメソッドを利用する。
本APIはiOS5.0から利用可能。

第3引数completionHandlerにはデータ取得時に実行するBlock文を記述する。このBlock文は第2引数queueで指定したNSOperationQueue上で実行される。以下のコード例ではBlock文はメインスレッドで実行されることになる。

環境
  • Xcode 4.6.3
  • ARC ON
  • iPhone 6.1 Simulator
#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

@property (weak, nonatomic) IBOutlet UITextField *requestUrl;
@property (weak, nonatomic) IBOutlet UITextField *requestBody;
@property (weak, nonatomic) IBOutlet UITextView *requestResult;
- (IBAction)getAsync:(id)sender;
- (IBAction)postAsync:(id)sender;

@end
#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

// HTTP-GET
- (IBAction)getAsync:(id)sender {
    NSLog(@"%@#%@", NSStringFromClass([self class]), NSStringFromSelector(_cmd));

    // Create the url-request.
    NSURL *url = [NSURL URLWithString:self.requestUrl.text];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

    // Set the method(HTTP-GET)
    [request setHTTPMethod:@"GET"];

    // Send the url-request.
    [NSURLConnection sendAsynchronousRequest:request
                                       queue:[NSOperationQueue mainQueue]
                           completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {   
        if (data) {
            NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"result: %@", result);
            self.requestResult.text = result;
        } else {
            NSLog(@"error: %@", error);
            self.requestResult.text = [NSString stringWithFormat:@"error: %@", error];
        }
    }];
    
}

// HTTP-POST
- (IBAction)postAsync:(id)sender {
    NSLog(@"%@#%@", NSStringFromClass([self class]), NSStringFromSelector(_cmd));

    // Create the url-request.
    NSURL *url = [NSURL URLWithString:self.requestUrl.text];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

    // Set the header(s).
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];

    // Set the method(HTTP-POST)
    [request setHTTPMethod:@"POST"];

    // Set the request-body.
    NSString *reqBody = self.requestBody.text;
    NSLog(@"reqBody: %@", reqBody);
    [request setHTTPBody:[reqBody dataUsingEncoding:NSUTF8StringEncoding]];

    // Send the url-request.   
    [NSURLConnection sendAsynchronousRequest:request
                                       queue:[NSOperationQueue mainQueue]
                           completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
        
        if (data) {
            NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"result: %@", result);
            self.requestResult.text = result;
        } else {
            NSLog(@"error: %@", error);
            self.requestResult.text = [NSString stringWithFormat:@"error: %@", error];
        }
    }];
  
}

@end

2013年4月26日金曜日

Node.jsをアンインストールする

OS X用インストーラ(.pkg)を使ってインストールしたNode.jsをアンインストールする。


はじめに削除すべきディレクトリ、ファイルを確認する。


/usr/local/bin(下記ファイルを削除する。モジュール導入環境によって異なる。)
lrwxr-xr-x    express -> ../lib/node_modules/express/bin/express
-rwxr-xr-x    node
-rwxr-xr-x    node-waf
lrwxr-xr-x    npm -> ../lib/node_modules/npm/bin/npm-cli.js

/usr/local/include(下記ディレクトリを削除する)
drwxr-xr-x    node

/usr/local/lib/dtrace(本ディレクトリごと削除する)
-rw-r--r--    node.d

/usr/local/lib/node(本ディレクトリごと削除する)
drwxr-xr-x    wafadmin

/usr/local/lib/node_modules(本ディレクトリごと削除する。モジュール導入環境によって異なる。)
drwxr-xr-x    express
drwxr-xr-x    npm

/usr/local/share/man/man1(下記ファイルを削除する)
-rw-r--r--    node.1

/var/db/receipts(下記ファイルを削除する)
-rw-r--r--    org.nodejs.node.npm.pkg.bom
-rw-r--r--    org.nodejs.node.npm.pkg.plist
-rw-r--r--    org.nodejs.pkg.bom
-rw-r--r--    org.nodejs.pkg.plist

~/(下記ディレクトリを削除する。プロキシ等を設定している場合は.npmrcファイルも削除する。)
drwxr-xr-x    .node-gyp
drwxr-xr-x    .npm
drwxr-xr-x    .sourcemint


実際に削除を行う。


有用なスクリプトがあるので利用する。
$ curl -ks https://gist.github.com/nicerobot/2697848/raw/uninstall-node.sh
$ chmod u+x uninstall-node.sh 
$ ./uninstall-node.sh 
$ rm uninstall-node.sh 
[参考URL]Mac OS X uninstall script for packaged install of node.js

上記スクリプトの対象となっていないディレクトリ・ファイルを手動で削除する(プロキシ等を設定している場合は.npmrcファイルも要手動削除)。
$ sudo rm -rf /usr/local/include/node
$ sudo rm -rf /usr/local/lib/dtrace
$ rm -rf ~/.node-gyp
$ rm -rf ~/.npm
$ rm -rf ~/.sourcemint

2013年1月22日火曜日

プロキシ環境下でnpm installを実行する

書式
$ npm config set proxy http://プロキシサーバのURL:ポート番号

具体例
$ npm config set proxy http://proxy.example.com:8080

上記コマンドを実行するとホームディレクトリに.npmrcというファイルが作成される。
$ less ~/.npmrc

~/.npmrc
proxy = http://proxy.example.com:8080

上記の通りプロキシを設定してもエラーが出る場合には、さらに下記コマンドを実行する。
$ npm config set registry http://registry.npmjs.org/