Cocoa練習帳 -32ページ目

[iOS]ユーザに選択させる(UIActionSheet)

前回のアラートは、ユーザに情報を伝える為のもの。今回のアクション・シートはユーザに選択させる為のものだ。




ビューコントローラにUIActionSheetDelegateプロトコルを設定する。




@interface ViewController : UIViewController <UIActionSheetDelegate>
@end



アクションシートを表示させる。




@implementation ViewController
 
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    UIActionSheet   *actionSheet = [[UIActionSheet alloc] initWithTitle:@"My Action Sheet"
                                                               delegate:self
                                                      cancelButtonTitle:@"Cancel"
                                                 destructiveButtonTitle:@"destructive button"
                                                      otherButtonTitles:@"Button 1",
                                                                        @"Button 2", 
                                                                        nil];
    [actionSheet showInView:self.view];
}
 
@end



アラートと同様にアクション・シートもデリゲートのメソッドでボタン押下に対応する。




@implementation ViewController
  
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
    NSLog(@"%s index(%d)", __func__, (int)buttonIndex);
}
 
- (void)actionSheetCancel:(UIActionSheet *)actionSheet
{
    NSLog(@"%s", __func__);
}
 
@end



実行。




アクションシート




アクション・シートでは、追加するボタンの個数は可変だ。画面に収まりきれなく個数を指定した場合は、どうなるのだろうか?




@implementation ViewController
 
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    UIActionSheet   *actionSheet = [[UIActionSheet alloc] initWithTitle:@"My Action Sheet"
                                                               delegate:self
                                                      cancelButtonTitle:@"Cancel"
                                                 destructiveButtonTitle:@"destructive button"
                                                      otherButtonTitles:@"Button 1",
                                                                        @"Button 2",
                                                                        @"Button 3",
                                                                        @"Button 4",
                                                                        @"Button 5",
                                                                        @"Button 6", 
                                                                        nil];
    [actionSheet showInView:self.view];
}
 
@end



ピッカー




なんと、ボタンの部分がピッカーになっている!




第50回関東Cocoa勉強会で@saeki24hさんが、自身が発見されたアクション・シートのバグを発表されていましたが、その時はボタンの個数が増えてピッカーになった際に、cancelボタンとdestructiveボタンの順番が変わって、その際、インデックスがおかしくなっていたが、iOS 5.1で修正されたのか、ボタンの順番が変わらず、その為か、インデックスは正しい値のようだ。






関連情報
UIActionSheet Class Reference

UIActionSheetDelegate Protocol Reference

[iOS]アラートを表示する

ビーコントローラでタッチ操作を検出するようにして、タッチされたら、OKボタンのみのアラートを表示する例だ。




ビューコントローラにプロトコルを使って、UIAlertViewDelegateへ対応させる。




@interface ViewController : UIViewController <uialertviewdelegate>
@end



タッチされたらOKボタンのみのシンプルなアラートを表示させる。




@implementation ViewController
 
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Demo Alert"
                                                    message:@"demo appl"
                                                   delegate:self
                                          cancelButtonTitle:nil
                                          otherButtonTitles:@"OK", nil];
    [alert show];
}
 
@end



OKボタンが押下されたら呼び出される、デリゲートのメソッドを追加する。




@implementation ViewController
  
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    NSLog(@"- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex(%d)", (int)buttonIndex);
}
 
@end



実行。




alert





関連情報

UIAlertView Class Reference

UIAlertViewDelegate Protocol Reference

[iOS]CoreAnimation(animating transitions)

画像に続いて文字列に対しても、何らかの画面上の効果を発生させたいと考えている。今、考えているのは、UILabeに対してだ。


前回までのUIViewに対してのアニメーションだと、対象のプロパティがアニメーションになるのだが、今回は効果に対応するプロパティを変更する必要が無い。変更したら、完了後に戻す処理が必要になる。


今、考えている事に合う手段はないか?と、探していて見つけたのだ、レイヤへの効果の適用だ。




まず、Quartz Coreフレームワークをプロジェクトに追加する。そして、QuartzCore/QuartzCore.hをインポートする。




サンプルではラベルの内容の変化が分かるように日付を設定している。




ラベルに現在日時を初期値として設定する。




- (void)awakeFromNib
{
    NSDate  *date = [NSDate date];
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateStyle:NSDateFormatterMediumStyle];
    [formatter setTimeStyle:NSDateFormatterMediumStyle];
    self.label.text = [formatter stringFromDate:date];
}



画面がタッチされたら、ラベルの内容を現在日時に変更して、アニメーションを実行する。




- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    CATransition    *animation = [CATransition animation];
    [animation setDelegate:self];
    [animation setDuration:1.0f];
    [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
    [animation setType:kCATransitionPush];
    [animation setSubtype:kCATransitionFromLeft];
    NSDate  *date = [NSDate date];
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateStyle:NSDateFormatterMediumStyle];
    [formatter setTimeStyle:NSDateFormatterMediumStyle];
    self.label.text = [formatter stringFromDate:date];
    [[self.label layer] addAnimation:animation forKey:@"animation transition"];
}



文字が左から右に流れた後に、内容が変わる事が確認できるはずだ。




ソースコード

GitHubからどうぞ。

https://github.com/murakami/workbook/tree/master/ios/CoreAnimation - GitHub




関連情報

Core Animation for Mac OS X and the iPhone

Creating Compelling Dynamic User Interfaces

Core Animationプログラミングガイド

アニメーションのタイプとタイミング

iOS Developer Libraryの翻訳文書だ。

[iOS]CoreAnimation(flip view)

画面に表示する画像を差し替える場合、カードをめくるような効果を使える例だ。




- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    [UIView beginAnimations:@"flip view" context:nil];
    [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft
                           forView:self.imageView
                             cache:YES];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
    [UIView setAnimationDuration:1.0];
    if (self.isAtMark) {
        self.isAtMark = NO;
        self.imageView.image = self.arrowImage;
        
    }
    else {
        self.isAtMark = YES;
        self.imageView.image = self.atmarkImage;        
    }
    [UIView commitAnimations];
}



前回の例との差は、transitionとタイミングの指定の追加だ。




ソースコード

GitHubからどうぞ。

https://github.com/murakami/workbook/tree/master/ios/CoreAnimation - GitHub




関連情報

Core Animation for Mac OS X and the iPhone

Creating Compelling Dynamic User Interfaces

Core Animationプログラミングガイド

アニメーションのタイプとタイミング

iOS Developer Libraryの翻訳文書だ。

[iOS]iOS 5.1

今回は、iOS 5.1リリースに伴う、開発環境の更新に時間がかかっているため、いつもの練習が行えない。そこで、Developerサイトで見つけたページを紹介する。




iOSがバージョンアップすると、Xcodeもバージョンアップしないと、実機での動作確認が行えない。何時も、Xcodeのバージョンアップの方が少し遅れて始まるので、リリースを控えている場合は注意が必要だ。




そして、iOSがバージョナップすると、Xcodeのバージョンアップは必要か?ターゲットは、以前のバージョンのOSからなので、Xcodeのバージョンアップは?ということが話題になるように思えるが、その疑問に答えるサイトだ。




Create Aps for  iOS 5.1


以前のADC時代から考えると、本当に最近のApple Developerサイトは、親切になったね!


[iOS]CoreAnimation(animation block)

CoreAnimationは奥が深い。その為、申し訳ないが、今、開発中のアプリケーションで利用しそうな機能を中心に取り上げてゆく。今回はアニメーション・ブロック。




画面をタッチすると、タッチした位置に画像が移動するコードだ。




- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = touches.anyObject;
    [UIView beginAnimations:@"center" context:nil];
    self.atMarkImageView.center = [touch locationInView:self];
    [UIView commitAnimations];
}



beginAnimations:context:とcommitAnimationsに囲まれた部分がブロックだ。ブロック内に記述されたUIViewの変更内容がアニメーションとなる。




ソースコード
GitHubからどうぞ。

https://github.com/murakami/workbook/tree/master/ios/CoreAnimation - GitHub


関連情報
Core Animation for Mac OS X and the iPhone

Creating Compelling Dynamic User Interfaces

Core Animationプログラミングガイド

アニメーションのタイプとタイミング

iOS Developer Libraryの翻訳文書だ。

[iOS]文字列を描画する

iOSでは文字列を描画する方法が複数あるが、それぞれ、長所と短所があるので、適材適所で使い分ける事が大事なようだ。




UILabelを使用する方法。単に描画したいだけなので、ビューでなくてもと思うかもしれないが、高機能なので便利だ。




- (void)viewDidLoad
{
    [super viewDidLoad];
     
    self.label = [[UILabel alloc] initWithFrame:CGRectMake(10.0, 100.0, 200, 50)];
    self.label.font = [UIFont systemFontOfSize:48.0];
    self.label.text = @"UILabel";
    self.label.adjustsFontSizeToFitWidth = YES;
    [self.view addSubview:self.label];
}



UIViewのサブクラスを作成して、-drawRect:で、NSStringのUIKit Additionsで描画するのも手軽だ。




- (void)drawRect:(CGRect)rect
{
    NSString    *str = @"NSString";
    [str drawAtPoint:CGPointMake(10.0, 20.0) withFont:[UIFont systemFontOfSize:48.0]];
}



CoreGraphicsを使う方法もあるが、日本語の扱いや、座標の扱いが難しいので、理由が無い限りはお勧めできない。




- (void)drawRect:(CGRect)rect
{
    CGContextRef    context = UIGraphicsGetCurrentContext();
    CGContextSaveGState(context);
        
    CGFloat height = self.bounds.size.height;
    CGContextTranslateCTM(context, 0.0, height);
    CGContextScaleCTM(context, 1.0, - 1.0);
    
    CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB();
    CGContextSetFillColorSpace(context, cs);
    CGColorSpaceRelease(cs);
        
    CGContextSetTextDrawingMode(context, kCGTextFill);
    CGContextSetRGBFillColor(context, 0.0, 0.0, 0.0, 1.0);
    
    CGContextSelectFont(context, "Helvetica", 48.0, kCGEncodingMacRoman);
    CGContextShowTextAtPoint(context, 10.0, 10.0, "Quartz", strlen("Quartz"));
 
    CGContextFlush(context);
    CGContextRestoreGState(context);
}



これら三つを使って文字列を描画した例だ。

DrawString





ソースコード
GitHubからどうぞ。

https://github.com/murakami/workbook/tree/master/ios/DrawString - GitHub


関連情報
iOS描画および印刷ガイド

Apple Developerサイトの情報。日本語に翻訳されている。

MOSADeN Online:「iPhoneアプリ初級脱出Online:高橋政明」

豊平文庫アプリケーションの高橋さんの記事。丁寧な説明で参考になる。


[iOS]イベント駆動のXMLプログラミング(その2)

前回の続き。用語を整理する。


エレメントは以下の初期となる。




<タグ>内容</タグ>



エレメントとは、タグで囲まれたデータという事になる。




XMLデータを頭から処理していき、エレメントに到達すると- parser:didStartElement:namespaceURI:qualifiedName:attributes:が呼ばれる。そのエレメントの内容に到達すると- parser:foundCharacters:が呼ばれるイメージだ。




XMLデータは木構造となるが、SAXではイベント駆動でデリゲートのメソッドが呼ばれるので、アプリケーション側で木構造を意識して処理する事になる。




例えば、以下のようなXMLデータ。




<?xml version= "1.0" encoding="UTF8">
<article author="Yukio MURAKAMI">
    <para>とても短い文章。</para>
</article>




  1. 処理開始

  2. エレメントarticleの開始タグが得られる。

  3. エレメントarticleの属性authorと値"Yukio MURAKAMI"が得られる。

  4. エレメントparaの開始タグが得られる。エレメントarticleの終了タグはまだなので、paraはarticleに包含されている事が分かる。

  5. エレメントparaの内容”とても短い文書。”が得られる。

  6. エレメントparaの終了タグが得られる。

  7. エレメントarticleの終了タグが得られる。

  8. 処理終了




ソースコード
GitHubからどうぞ。

https://github.com/murakami/workbook/tree/master/ios/XMLParser - GitHub


関連情報
Event-Driven XML Programming Guide

Apple Developerサイトの情報。

[iOS]イベント駆動のXMLプログラミング

XMLデータを操作するAPIに、DOM(Document Object Model)とSAX(Simple API for XML)があるが、これに対応するCocoaのクラスがNSXMLDocumentとNSXMLParserだ。ただし、iOSではNSXMLDocumentが利用できない。iOSでDOMを使用したい場合はlibxml2を利用する事になる。




XMLデータからエレメント名と値を取得する例は、以下のとおり。




ビュー・コントローラをNSXMLParserDelegateに対応させる。




@interface ViewController : UIViewController 
@property (strong, nonatomic) NSString  *elementName;
@end



指定されたURLのXMLデータを読み込み、エレメントとそれの値を見つけたらデバッグ出力する例だ。




@implementation ViewController
 
@synthesize elementName = _elementName;
 
- (void)viewDidLoad
{
    [super viewDidLoad];
     
    NSString    *requestString = [NSString stringWithString:@"http://www.kyuden.co.jp/power_usages/xml/electric_power_usage20120304.xml"];
    NSURL   *url = [NSURL URLWithString:requestString];
    [self parseXMLFile:url];
}
 
- (void)parseXMLFile:(NSURL *)url
{
    NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
    [parser setDelegate:self];
    [parser parse];
}
 
- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
  namespaceURI:(NSString *)namespaceURI
 qualifiedName:(NSString *)qualifiedName
    attributes:(NSDictionary *)attributeDict
{
    if (elementName) {
        NSLog(@"element: %@", elementName);
        self.elementName = elementName;
    }
}
 
- (void)parser:(NSXMLParser *)parser
 didEndElement:(NSString *)elementName
  namespaceURI:(NSString *)namespaceURI
 qualifiedName:(NSString *)qName
{
    if (self.elementName) {
        self.elementName = nil;
    }
}
 
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
    if ((self.elementName)
        && (![self.elementName isEqualToString:@""])
        && (string)) {
        NSLog(@"char: %@", string);
    }
}
@end



これ以上については著者も調査中なので、機会があれば次回で。




ソースコード
GitHubからどうぞ。

https://github.com/murakami/workbook/tree/master/ios/XMLParser - GitHub


関連情報
Event-Driven XML Programming Guide

Apple Developerサイトの情報。

[Mac][iOS]zlib ファイルの圧縮と解凍

zipファイルの操作でなく、メモリ上のデータを圧縮/解凍するには、どんな方法がいいのか?


以前、zlibの解説文章を読んだ事があり、全く難解で理解できなかったトラウマがあって、zlibを直接利用する事は避けていたのだが、今、改めて調べてみると、それ程、怖がるものではないように感じている。


という訳で、今回は、直接、zlibを利用する話だ。




OS X / iOSでzlibを利用するのは、簡単だ。"libz.dylib"をプロジェクトに追加するだけでいい。


データを圧縮するコードは以下のとおり。




 #define OUTBUFSIZ   1024
 
- (void)zip:(NSString *)path
{
    NSMutableData   *data = [[NSMutableData alloc] init];
    z_stream   strm;
    strm.zalloc = Z_NULL;
    strm.zfree = Z_NULL;
    strm.opaque = Z_NULL;
    deflateInit(&strm, Z_DEFAULT_COMPRESSION);
    char    str[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    strm.next_in = (Bytef *)str;
    strm.avail_in = strlen(str);
    char    buffer[OUTBUFSIZ];
    strm.next_out = (Bytef *)buffer;
    strm.avail_out = OUTBUFSIZ;
 
    int status;
    for (;;) {
        if (strm.avail_in == 0) {
            status = deflate(&strm, Z_FINISH);
        }
        else {
            status = deflate(&strm, Z_NO_FLUSH);
        }
        if (status == Z_STREAM_END) {
            break;
        }
        if (status != Z_OK) {
            DBGMSG(@"deflate: %s", (strm.msg) ? strm.msg : "error");
            break;
        }
        if (strm.avail_out == 0) {
            [data appendBytes:buffer length:OUTBUFSIZ];
            strm.next_out = (Bytef *)buffer;
            strm.avail_out = OUTBUFSIZ;
        }
    }
    if (strm.avail_out != OUTBUFSIZ) {
        [data appendBytes:buffer length:(OUTBUFSIZ - strm.avail_out)];
    }
    deflateEnd(&strm);
    //[data writeToFile:path atomically:YES];
}



文字列strを圧縮するコードだ。圧縮したデータを保存する様にしてみたのだが、これだけだと、zip形式のファイルにならないようで、unzip出来ないので、コメントアウトしている。




ソースコード
GitHubからどうぞ。

https://github.com/murakami/workbook/tree/master/mac/Zip


関連情報
zlib

A Massively Spiffy Yet Delicately Unobtrusive Compression Library

Minizip

Zip and UnZIp additionnal library

ZipArchive

An Objective C class for zip/unzip on iPhone and Mac OSX

objective-zip

An iOS wrapper for ZLib and MiniZip

Objective-CでZIPアーカイブを読み取る

@marvelphさんのブログです。

Objective-Cでzlibを使った圧縮

分かりやすくていい。初めの情報として助かった。

zlib入門

丁寧な説明とサンプルが参考になった。