tag:blogger.com,1999:blog-68973519860592273822024-03-14T13:14:38.649+09:00erプログラムとかのメモ、メモ、メモ、、、不正確情報満載、、、目立たないようにこっそりと。本家は blog.eyesrobe.com だけど更新してない。eyesrobehttp://www.blogger.com/profile/04737958288797616975noreply@blogger.comBlogger43125tag:blogger.com,1999:blog-6897351986059227382.post-31862261158466836812011-02-20T11:01:00.002+09:002011-02-20T11:03:40.004+09:00仕事の面接に行ってきた。真剣に入りたい会社だったのでログを残しておく。<br />受かっても受からなくても、ここが人生の転機になりそうな予感あり。eyesrobehttp://www.blogger.com/profile/04737958288797616975noreply@blogger.com0tag:blogger.com,1999:blog-6897351986059227382.post-89512494077681475792011-02-20T11:00:00.003+09:002011-02-20T11:03:49.145+09:00Moneyha 1.0.5を申請した昨日の昼間に申請した。<br /><br />金額にカンマが入るようにしただけ。eyesrobehttp://www.blogger.com/profile/04737958288797616975noreply@blogger.com0tag:blogger.com,1999:blog-6897351986059227382.post-45640228664816021282011-02-20T10:35:00.010+09:002011-02-20T10:59:20.092+09:00[request setReturnsObjectsAsFaults:NO]; を指定したら <fault>が消えた件CoreData使っててログを出力したら <fault>って出て困った。<br />詳細はわかってないし、詳細も書かないですけど、出なくなったのでメモ残しとく。<br /><pre name="code" class="c"><br />NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];<br />NSMutableArray *mutableFetchResults = [[[context executeFetchRequest:request error:&error] mutableCopy] autorelease];<br /></pre><br />executeFetchRequest:error: で取ってきた結果を NSLogで見てみると、dataの中身が<fault>になってる。実際は登録してあるtimeStampが入ってくるはずなのに。<br /><pre name="code" class="c"><br />"<NSManagedObject: 0x612da10> (entity: Event; id: 0x612ccc0 <x-coredata://61949995-D9C8-40AE-A339-D6C9FB160179/Event/p1> ; data: <fault>)"<br /></pre><br />調べてみると、<br /><pre name="code" class="c"><br />[request setReturnsObjectsAsFaults:NO];<br /></pre><br />を入れればいいと。入れてみた。データ取れてるの確認できた。<br /><pre name="code" class="c"><br />"<NSManagedObject: 0x6132890> (entity: Event; id: 0x6131ae0 <x-coredata://61949995-D9C8-40AE-A339-D6C9FB160179/Event/p1> ; data: {\n timeStamp = \"2011-02-19 12:54:27 +0000\";\n})"<br /></pre>eyesrobehttp://www.blogger.com/profile/04737958288797616975noreply@blogger.com0tag:blogger.com,1999:blog-6897351986059227382.post-2428944524891675342011-02-11T22:12:00.003+09:002011-02-11T22:18:41.908+09:00sizeofは型のサイズを返すだから、ポインター変数を指定した場合、ポインターの指している先に確保されているメモリサイズを返すのではなく、ポインターのサイズ(32bitCPUならたぶん4)が返る。<br /><pre name="code" class="c"><br />size_t sz = sizeof("abcdefghij"); // \nが含まれて 11<br /><br />const char *p = "abcdefghij";<br />size_t sz = sizeof(p); // 型のサイズ 4<br /><br />// 文字列の長さもとめるならstrlen<br />strlen("abcdefghij") // 10<br />strlen(p) // 10<br /></pre>eyesrobehttp://www.blogger.com/profile/04737958288797616975noreply@blogger.com0tag:blogger.com,1999:blog-6897351986059227382.post-72288598334716825382011-02-11T11:59:00.004+09:002011-02-11T12:16:16.754+09:00座標からtableViewのindexPathってわかる?わかる。<br /><br /><pre name="code" class="c"><br />// 表示しているtableVIewの現状のオフセットを取得する。<br />// ・tableVIewのオフセットはスクロールさせると値が変わるよ。<br />CGPoint offset = self.myTableView.contentOffset;<br /><br />// オフセットの位置からy軸に120ポイント下に座標を指定してみよう。<br />// ・この場合だと、見た目上(画面上)の(10, 120)の位置を常にCGPointで取得してるってこと。<br />CGPoint p = CGPointMake(10.0, 120.0 + offset.y); <br /><br />// で、オフセット分を調整した座標(p)からindexPathが取得できるようになると。<br />NSIndexPath *indexPath = [self.myTableView indexPathForRowAtPoint:p];<br /><br />NSLogPoint(offset);<br />NSLog(@"%d", indexPath.row);<br /><br />[self setDetailView:indexPath];<br /></pre><br /><br /><br />ついでに、スクロールしたときのドラッグ感知やスクロール停止時の感知のデリゲートメソッド<br /><pre name="code" class="c"><br />- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {<br />}<br /><br />- (void)scrollViewDidScroll:(UIScrollView *)scrollView {<br /> }<br /><br />- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {<br /> [self hogel];<br />}<br /><br />- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {<br /> if (!decelerate) {<br /> [self hoge];<br /> }<br />}<br /></pre>eyesrobehttp://www.blogger.com/profile/04737958288797616975noreply@blogger.com0tag:blogger.com,1999:blog-6897351986059227382.post-46774969735831127692011-01-17T22:49:00.002+09:002011-01-17T23:05:06.185+09:00Mac OSX10.6とHDDと復元とMacBook(白)(late2006)のHDD換装作業。<br />確か今回で3度目の交換になる。<br />80GB > 160GB > 320GB > 750GB<br />現在、2.5インチで1TBのHDDも出てるけど厚さが合わないので使えない。<br />9.5mm厚のもので最大容量は750GB、これに換装する。<br /><br />換装から復元までの今回の手順<br />1.320GBの内蔵HDDを750GBの新HDDに交換する<br />2.320GBのを外付けHDDケースに入れる<br />3.DVDからディスクユーティリティを起動する<br />4.750GBのにパーティションを作成する<br />5.パーティションを消去(初期化)する<br />6.2.の外付けHDDを接続する<br />7.復元タブを開いて、「復元先を消去」を外す。<br />8.ソースと復元先を、外付けHDDと内蔵HDDをそれぞれ選択する。<br />9.復元〜ん。<br />10.寝て起きたら終わってるはず。<br /><br />やりかたは色々ある。<br />80GB > 160GB へ換装したときは rsync を使って復元した。<br />160GB > 320GB へ換装したときも rsync を使って復元した。<br />320GB > 750GB へ今回換装するとき、最初はタイムマシンから復元する予定だった。<br />でも失敗したので今回やった方法で復元した。<br />後からもう少し調べたところ、タイムマシンからの復元は一度クリーンインストールした後に復元作業にすすむらしい。<br /><br />みんな好き好きな方法をでやってみればいい。eyesrobehttp://www.blogger.com/profile/04737958288797616975noreply@blogger.com0tag:blogger.com,1999:blog-6897351986059227382.post-81697703252465478902011-01-04T23:23:00.003+09:002011-01-04T23:26:21.634+09:00Moneyha 1.0.4を申請した今日の夕方。<br />完全なるバグ、修正したの申請した。<br />1月1日で新規登録が出来ないっていう最悪なバグ。バグバグ。<br />ごめんなさい。eyesrobehttp://www.blogger.com/profile/04737958288797616975noreply@blogger.com0tag:blogger.com,1999:blog-6897351986059227382.post-33501099810136419862011-01-04T22:00:00.017+09:002011-01-04T23:22:56.686+09:00YYYY じゃなくて yyyyバグが出るとすれば元日あたりに出るだろうなぁと思ったら出た。<br />Moneyha ってiPhoneアプリで出た。不具合出た。<br />レビューは優しさに満ち溢れていたのでとても嬉しかった。<br />(バグありなのに星4と3を付けてレビューしていただけた。)<br /><br />Objective-C でのはなし。 Xcode 3.2.5 and iOS SDK 4.2.1 で試してる。<br /><br />単純な話で、YYYY が間違いだった。 yyyy が正しい。<br /><pre name="code" class="c"><br />NSDateFormatter *formatter = [[NSDateFormatter alloc] init];<br />[formatter setDateFormat:@"yyyy"]; // ここを @"YYYY" ってしてた。<br /></pre><br />これだけだとなんなので、調べる過程で出てきた NSDate のポイントをいくつか。<br /><pre name="code" class="c"><br />// とりあえずタイムゾーンを確かめておこうよ<br />NSLog(@"%@", [NSTimeZone defaultTimeZone]); // Asia/Tokyo (GMT+09:00) offset 32400<br /><br />// NSLogはタイムゾーン関係ないから注意。<br />NSLog(@"%@", [NSDate date]);<br /><br />// もうちょいわかり易く。<br />NSDateFormatter *formatter = [[NSDateFormatter alloc] init];<br />[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];<br />NSDate *d = [formatter dateFromString:@"2011-01-01 00:00:00"]; // d は日本時間だよ<br />NSLog(@"%@", [formatter stringFromDate:d]); // 当然 2011-01-01 00:00:00<br />NSLog(@"%@", d); // こっちは? 2010-12-31 15:00:00 +0000 が正解。タイムゾーンは日本じゃなくてグリニッジ標準時。<br /></pre><br /><br />そんな感じで。<br /><br />YYYY と yyyy の違いはこちらの方のブログに書かれてました。ありがとう。<br />『NSDateFormatterのYYYY利用時の注意点』<br />http://d.hatena.ne.jp/mmasashi/20101111/1289489570eyesrobehttp://www.blogger.com/profile/04737958288797616975noreply@blogger.com0tag:blogger.com,1999:blog-6897351986059227382.post-76060965653856588212010-12-14T16:04:00.004+09:002010-12-14T20:00:02.147+09:00RSS2.0 の pubDate に入ってる日付を NSDate に変換したい。Objective-C での変換のはなし。 Xcode 3.2.5 and iOS SDK 4.2.1 で試してる。<br />文字列の日付を NSDate に変換します。<br /><br /><br />こんな感じで。<br /><pre name="code" class="c"><br />NSString *stringPubDate = @"Tue, 30 Nov 2010 06:54:00 +0000";<br /> <br />NSDateFormatter *formatter = [[NSDateFormatter alloc] init];<br />[formatter setDateFormat:@"EEE, dd MMM yyyy HH:mm:ss ZZZZ"];<br />NSDate *pubDate = [formatter dateFromString:stringPubDate];<br />[formatter release];<br /> <br />NSLog(@"%@", pubDate);<br /></pre><br /><br /><br />EEEを探すのに苦労した。<br />記号の一覧がまとまってるサイトを探してたけど、見つけられなかった。<br /><br />EEEが見つかる前は仕方ない、こんな感じにしようと思った。<br /><pre name="code" class="c"><br />NSString *stringPubDate = @"Tue, 30 Nov 2010 06:54:00 +0000";<br /><br />NSArray *splitDate = [stringPubDate componentsSeparatedByString:@", "];<br /><br />NSDictionary *weekDict = [NSDictionary dictionaryWithObjectsAndKeys:<br /> @"月", @"Mon",<br /> @"火", @"Tue",<br /> @"水", @"Wed",<br /> @"木", @"Thu",<br /> @"金", @"Fri",<br /> @"土", @"Sat",<br /> @"日", @"Sun",nil];<br /> <br />NSDateFormatter *formatter = [[NSDateFormatter alloc] init];<br />[formatter setDateFormat:@"dd MMM yyyy HH:mm:ss ZZZZ"];<br />NSDate *pubDate = [formatter dateFromString:[splitDate objectAtIndex:1]];<br />[formatter release];<br /> <br />NSLog(@"%@ %@曜日", pubDate, [weekDict objectForKey:[splitDate objectAtIndex:0]]);<br /></pre><br /><br />ついでなので、NSDate から文字列に変換してみる。<br /><pre name="code" class="c"><br />NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];<br />[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:@"Asia/Tokyo"]];<br />[dateFormatter setDateFormat:@"yyyy年MM月dd日HH時mm分ss秒"];<br />NSString *stringPubDate = [dateFormatter stringFromDate:pubDate];<br />[dateFormatter release];<br /> <br />NSLog(@"pubDate [ %@ ] [ %@ ]", pubDate, stringPubDate);<br /></pre>eyesrobehttp://www.blogger.com/profile/04737958288797616975noreply@blogger.com0tag:blogger.com,1999:blog-6897351986059227382.post-29879130742616726182010-11-30T15:54:00.002+09:002010-11-30T15:57:02.655+09:00Moneyha 1.0.2 を申請した昨日の夕方。<br />iOS SDK 4.2.1 でリビルドしただけのバージョン。<br /><br />次期バージョンとしていくつか新機能を試していたけど、ちょっと考え直す。<br />締め日を変更できるようにして欲しいっていうレビューあり。<br />簡単に対応できるか調べてみる。eyesrobehttp://www.blogger.com/profile/04737958288797616975noreply@blogger.com0tag:blogger.com,1999:blog-6897351986059227382.post-18534250323840177962010-11-30T15:24:00.006+09:002010-11-30T21:48:05.415+09:00設定ファイルをplistで用意しておいて読み書きさせたいXcodeに追加したplistファイル。<br />これをアプリ側で読み書きさせたい。<br /><br />こうやるっぽい。<br />・Document ディレクトリーにplistファイルをコピーして使う。<br /><br />合ってるかわからないが、こうやってみた。<br />・plistファイルをコピーするDocument ディレクトリへのパスを取得する。<br />・そのパスにファイルがあるか確認する。<br />・ない。アプリを初めて起動するときは、ない。<br />・そのパスのファイルを作成する。(plistファイルをコピーして作成する。)<br />・以降は作成した(Document ディレクトリにある)ファイルを読み書きする。<br /><br /><br /><pre name="code" class="c"><br />//<br />// かなーりコードを省略してます。当然ですがコピペしても動きませんよ。<br />//<br />@interface HogeAppDelegate : NSObject <UIApplicationDelegate, UITabBarControllerDelegate><br />{<br /> @private<br /> NSString *filepathToHogePlist_;<br />}<br /><br />@property (nonatomic, retain, readonly) NSString *filepathToHogePlist;<br /><br />- (NSString *)applicationDocumentsDirectory;<br /><br />@end<br /></pre><br /><pre name="code" class="c"><br />//<br />// かなーりコードを省略してます。当然ですがコピペしても動きませんよ。<br />//<br />@implementation HogeAppDelegate<br /><br />@synthesize filepathToHogePlist = filepathToHogePlist_;<br /><br />//<br />// [self applicationDocumentsDirectory] でDocument ディレクトリへのパスが取得できる<br />//<br />- (NSString *)applicationDocumentsDirectory<br />{<br /> return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];<br />}<br /><br />//<br />// アプリを初めて使うときに、plistをコピーしている。<br />//<br />// NSArray *hoges = [NSArray arrayWithContentsOfFile:self.filepathToHogePlist];<br />// とか <br />// [hogehogehoge writeToFile:self.filepathToHogePlist atomically:YES];<br />// みたいな感じで処理できるようになる。<br />//<br />- (NSString *)filepathToHogePlist<br />{<br /> if (filepathToHogePlist_!=nil) {<br /> return filepathToHogePlist_;<br /> }<br /> <br /> BOOL success;<br /> NSFileManager* fileManager = [NSFileManager defaultManager]; <br /> filepathToHogePlist_ = [[self applicationDocumentsDirectory] stringByAppendingPathComponent:@"Hoge.plist"];<br /><br /> // アプリで用意したファイル(これをDocumentDirectoryにコピーして、以降はコピーしたファイルを読み書きさせる)<br /> success = [fileManager fileExistsAtPath:filepathToHogePlist_];<br /> if (!success)<br /> {<br /> NSBundle* bundle = [NSBundle mainBundle];<br /> NSString* bundlepath = [bundle pathForResource:@"Hoge" ofType:@"plist"];<br /> NSMutableArray *hoges = [NSMutableArray arrayWithContentsOfFile:bundlepath];<br /> [hoges writeToFile:filepathToHogePlist_ atomically:YES]; <br /> }<br /> <br /> return [filepathToHogePlist_ retain];<br />}<br /><br />@end<br /><br /></pre><br /><br />こんな感じで。なんとなく。<br /><br />で、iOSシミュレータの場合のDocumentDirectoryの場所<br />~/Library/Application Support/iPhone Simulator/バージョン/Applications/ランダムな文字列/Documents/Hoge.plisteyesrobehttp://www.blogger.com/profile/04737958288797616975noreply@blogger.com0tag:blogger.com,1999:blog-6897351986059227382.post-62254203844013671002010-11-08T17:37:00.011+09:002010-11-10T14:59:36.408+09:00View-based Application で CoreData を使えるようしたい新規プロジェクト作成のテンプレートでView-based Applicationを選択してプロジェクトを作成する。Core Dataを使いたいがどうすればいいのか。<br />Navigation-based Applicationテンプレートを選ぶ場合はCore Dataを使うかどうか選択できるようになってるけど、View-basedではチェックボックスが出てこない。<br />それならば自分で実装しようということになるのだけれど、うーんうーんって感じになる場合が多いと思うの。<br /><br />なので手順を書いておく。<br /><br />Xcode 3.2.4 and iOS SDK 4.1 で試してる。<br />古いバージョンとか新しいバージョンのこと考えてない。<br /><br />新規プロジェクトをView-based Applicationを選択して名前をMyCDataとして作成してます。<br /><br /><br />僕がやったポイント。<br /><br /><ol><li>CoreData.frameworkを追加<br /><li>DataModel(.xcdatamodel)ファイルを新規作成<br /><li>DataModelにエンティティ作ってプロパティを追加<br /><li>.xcdatamodelを.xcdatamodeldにバンドル<br /><li>Managed Object Class(NSManagedObjectサブクラス)ファイルを新規作成<br /><li>おまじないのコード(NSManagedObjectContextなどを用意)<br /><li>後は普通にコード書く<br /><li>データの読み込みや追加などは、用意したコンテクスト(NSManagedObjectContext)を通じて実行<br /></ol><br /><br /><br /><strong>1.Frameworksグループを右クリック>追加>既存のフレームワーク>CoreData.frameworkを追加</strong><br /><br /><strong>2.Resourcesグループを右クリック>追加>新規ファイル>DataModelを選択>MyCData.xcdatamodelと名前付けて次へでそのまま完了。</strong><br /><br /><strong>3.MyCData.xcdatamodelにエンティティPersonを追加して、そのプロパティにageとnameを追加。</strong><br /><br />データ型を<br />age は Int16<br />name は String<br />とした。<br /><br /><strong>4.MyCData.xcdatamodelを選択した状態で、設計>データモデル>モデルバージョンを追加。</strong><br /><br />MyCData.xcdatamodeldにMyCData.xcdatamodelがバンドルされた形になる。<br />MyCData.xcdatamodeldの中にxcdatamodelファイルが1つ追加されるけどいらないので削除する。<br /><br />※この4.をやらないで対応する方法もあるけれどそれは書かない。将来的にモデルの変更(プロパティの追加など)がされる可能性を考えれならこれやっとけばいいじゃん、必要になるでしょってことで。<br /><br /><br /><strong>5.エンティティPersonを選択した状態でファイル追加をするとManaged Object Classが選べるので、そのまま完了するとPerson.h/.mが追加される。</strong><br /><pre name="code" class="c"><br />//<br />// Person.h<br />//<br />#import <CoreData/CoreData.h><br /><br /><br />@interface Person : NSManagedObject <br />{<br />}<br /><br />@property (nonatomic, retain) NSNumber * age;<br />@property (nonatomic, retain) NSString * name;<br /><br />@end<br /></pre><br /><pre name="code" class="c"><br />// <br />// Person.m<br />//<br /><br />#import "Person.h"<br /><br /><br />@implementation Person <br /><br />@dynamic age;<br />@dynamic name;<br /><br />@end<br /></pre><br /><br /><br /><strong>6.おまじないコード</strong><br /><br /><pre name="code" class="c"><br />//<br />// MyCDataAppDelegate.h<br />//<br />#import <UIKit/UIKit.h><br /><br />// ここ追加<br />#import <CoreData/CoreData.h><br /><br />@class MyCDataViewController;<br /><br />@interface MyCDataAppDelegate : NSObject <UIApplicationDelegate> {<br /> UIWindow *window;<br /> MyCDataViewController *viewController;<br />// ここ追加<br />@private<br /> NSManagedObjectContext *managedObjectContext_;<br /> NSManagedObjectModel *managedObjectModel_;<br /> NSPersistentStoreCoordinator *persistentStoreCoordinator_;<br />}<br /><br />@property (nonatomic, retain) IBOutlet UIWindow *window;<br />@property (nonatomic, retain) IBOutlet MyCDataViewController *viewController;<br /><br />// ここ追加<br />@property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;<br />@property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel;<br />@property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;<br /><br />// ここ追加<br />- (NSString *)applicationDocumentsDirectory;<br /><br />@end<br /></pre><br /><pre name="code" class="c"><br />//<br />// MyCDataAppDelegate.m<br />//<br />#import "MyCDataAppDelegate.h"<br />#import "MyCDataViewController.h"<br /><br />@implementation MyCDataAppDelegate<br /><br />@synthesize window;<br />@synthesize viewController;<br /><br /><br />#pragma mark -<br />#pragma mark Application lifecycle<br /><br />/**<br /> これ追加<br /> */<br />- (void)awakeFromNib { <br /> viewController.managedObjectContext = self.managedObjectContext;<br />}<br /><br />- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { <br /> [window addSubview:viewController.view];<br /> [window makeKeyAndVisible];<br /> return YES;<br />}<br /><br />- (void)applicationWillResignActive:(UIApplication *)application {<br />}<br /><br />- (void)applicationDidEnterBackground:(UIApplication *)application {<br />}<br /><br />- (void)applicationWillEnterForeground:(UIApplication *)application {<br />}<br /><br />- (void)applicationDidBecomeActive:(UIApplication *)application {<br />}<br /><br />- (void)applicationWillTerminate:(UIApplication *)application {<br />}<br /><br /><br />#pragma mark -<br />#pragma mark Memory management<br /><br />- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {<br />}<br /><br />- (void)dealloc {<br /> [viewController release];<br /> [window release];<br /> [super dealloc];<br />}<br /><br /><br />#pragma mark -<br />#pragma mark Core Data stack<br /><br />/**<br /> これ追加(ゲッター)<br /> CoreData用に共通のContextを1つここで用意する。<br /> SQLiteファイルへの永続ストアコーディネータ(NSPersistentStoreCoordinator)のインスタンスを、用意したContextにセットする。<br /> */<br />- (NSManagedObjectContext *)managedObjectContext {<br /> <br /> if (managedObjectContext_ != nil) {<br /> return managedObjectContext_;<br /> }<br /> <br /> NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];<br /> if (coordinator != nil) {<br /> managedObjectContext_ = [[NSManagedObjectContext alloc] init];<br /> [managedObjectContext_ setPersistentStoreCoordinator:coordinator];<br /> }<br /> return managedObjectContext_;<br />}<br /><br /><br />/**<br /> これ追加(ゲッター)<br /> .xcdatamodeld (.xcdatamodelを内包した)バンドルを指定する。<br /> 管理オブジェクトモデル(NSManagedObjectModel)の準備をする。<br /> この管理オブジェクトモデルを使うことで、管理オブジェクト(アプリ側)とレコード(データベース側)とのマッピングさせる。<br /> */<br />- (NSManagedObjectModel *)managedObjectModel {<br /> <br /> if (managedObjectModel_ != nil) {<br /> return managedObjectModel_;<br /> }<br /> <br /> NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"MyCData" ofType:@"momd"];<br /> NSLog(@"データモデルのバンドルディレクトリ(?)のパス %@", modelPath);<br /> NSURL *modelURL = [NSURL fileURLWithPath:modelPath];<br /> managedObjectModel_ = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; <br /> <br /> return managedObjectModel_;<br />}<br /><br />/**<br /> これ追加(ゲッター)<br /> 永続ストアとしてSQLite(ファイル)を指定する。<br /> この永続ストアコーディネータを使うことで、管理オブジェクトモデル(.xcdatamodel)と永続ストアを関連付けて管理できるようになる。<br /> */<br />- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {<br /> <br /> if (persistentStoreCoordinator_ != nil) {<br /> return persistentStoreCoordinator_;<br /> }<br /> <br /> NSURL *storeURL = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"MyCData.sqlite"]];<br /> <br /> <br /> NSError *error = nil;<br /> persistentStoreCoordinator_ = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];<br /> <br /> if (![persistentStoreCoordinator_ addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {<br /> NSLog(@"Unresolved error %@, %@", error, [error userInfo]);<br /> abort();<br /> } <br /> <br /> return persistentStoreCoordinator_;<br />}<br /><br /><br />#pragma mark -<br />#pragma mark Application's Documents directory<br /><br />/**<br /> これ追加<br /> Returns the path to the application's Documents directory.<br /> */<br />- (NSString *)applicationDocumentsDirectory {<br /> return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];<br />}<br /><br /><br />@end<br /></pre><br /><strong>7.後は普通にコード書く</strong><br /><strong>8.データの読み込みや追加などは、用意したコンテクスト(NSManagedObjectContext)を通じて実行</strong><br /><pre name="code" class="c"><br />//<br />// MyCDataViewController.h<br />//<br />#import <UIKit/UIKit.h><br /><br />// ここ追加<br />#import <CoreData/CoreData.h><br /><br />@interface MyCDataViewController : UIViewController {<br /> // ここ追加<br /> NSFetchedResultsController *fetchedResultsController_;<br /> NSManagedObjectContext *managedObjectContext_;<br /><br /> // ここ追加<br /> IBOutlet UIButton *addButton;<br /> IBOutlet UIButton *requestButton;<br /> NSMutableArray *persons;<br />}<br /><br /><br />// ここ追加<br />@property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;<br />@property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;<br /><br />// ここ追加<br />@property (nonatomic, retain) IBOutlet UIButton *addButton;<br />@property (nonatomic, retain) IBOutlet UIButton *requestButton;<br />@property (nonatomic, retain) NSMutableArray *persons;<br /><br />- (IBAction)addPerson:(id)sender;<br />- (IBAction)requestPersons:(id)sender;<br /><br />@end<br /></pre><br /><pre name="code" class="c"><br />//<br />// MyCDataViewController.m<br />//<br />#import "MyCDataViewController.h"<br /><br />// ここ追加<br />#import "Person.h"<br /><br />@implementation MyCDataViewController<br /><br />// ここ追加<br />@synthesize fetchedResultsController = fetchedResultsController_;<br />@synthesize managedObjectContext = managedObjectContext_;<br />@synthesize addButton;<br />@synthesize requestButton;<br />@synthesize persons;<br /><br />- (void)didReceiveMemoryWarning {<br /> [super didReceiveMemoryWarning];<br />}<br /><br />- (void)viewDidUnload {<br /> // ここ追加<br /> self.addButton = nil;<br /> self.requestButton = nil;<br />}<br /><br />- (void)dealloc {<br /> // ここ追加<br /> [addButton release];<br /> [requestButton release];<br /> [persons release];<br /> <br /> // ここ追加<br /> [fetchedResultsController_ release];<br /> [managedObjectContext_ release];<br /><br /> [super dealloc];<br />}<br /><br /><br />/**<br /> これ追加<br /> */<br />- (IBAction)addPerson:(id)sender<br />{<br /> NSLog(@"- (IBAction)addPerson:(id)sender");<br /> NSManagedObjectContext *context = self.managedObjectContext;<br /> <br /> Person *person = (Person *)[NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:context];<br /> <br /> [person setAge:[NSNumber numberWithInt:37]];<br /> [person setName:@"Jack"];<br /> <br /> NSError *error;<br /> if (![context save:&error]) {<br /> NSLog(@"Error");<br /> }<br />}<br /><br />/**<br /> これ追加<br /> */<br />- (IBAction)requestPersons:(id)sender<br />{<br /> NSLog(@"- (IBAction)requestPersons:(id)sender");<br /> NSManagedObjectContext *context = self.managedObjectContext;<br /> <br /> NSFetchRequest *request = [[NSFetchRequest alloc] init];<br /> NSEntityDescription *entity = [NSEntityDescription entityForName:@"Person" inManagedObjectContext:context];<br /> [request setEntity:entity];<br /> <br /> // ソート<br /> NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];<br /> NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];<br /> [request setSortDescriptors:sortDescriptors];<br /> [sortDescriptor release];<br /> [sortDescriptors release];<br /><br /> <br /> NSError *error;<br /> NSMutableArray *mutableFetchResults = [[context executeFetchRequest:request error:&error] mutableCopy];<br /> if (mutableFetchResults == nil) {<br /> NSLog(@"no results");<br /> }<br /> <br /> [self setPersons:mutableFetchResults];<br /> [mutableFetchResults release];<br /> [request release];<br /><br /><br /> for (Person *person in persons) {<br /> NSLog(@"%@", [person name]);<br /> }<br />}<br /><br />@end<br /></pre><br />後このサンプルでは、InterfaceBuilderでMyCDataViewController.xibにボタン2つ追加してそれぞれIBOutletとIBActionを繋げれば動くはず。eyesrobehttp://www.blogger.com/profile/04737958288797616975noreply@blogger.com0tag:blogger.com,1999:blog-6897351986059227382.post-71677789151559344292010-11-02T14:50:00.005+09:002010-11-10T14:06:34.448+09:00Objective-C + libxml2 を使ってフィードを取り込みたいんだ(9)なんかもうlibxml2のことは関係なく普通にObjective-Cの勉強になってる。<br /><br />今回は、<br /><ul><li>NSOperationQueue<br /><li>NSOperation<br /><li>NSNotificationCenter<br /><li>NSNotification<br /></ul><br />に焦点をあわせる。<br /><br />でもNSNotificationの辺りは<br />「Cocoa Notification (NSNotification,NSNotificationCenter)」と「キー値監視」(1~4)<br />に書いてるので省略。<br />1つだけ注意するのは、通知の受け取りをメインスレッドで行ないたい場合は、通知する側でperformSelectorOnMainThread:withObject:を使って通知を投げる必要あり。<br /><br /><br />NSOperationQueueとNSOperationについてもあまり書く事はないんだけど続ける。<br />覚えたこと。<br /><ul><li>並列と非並列とがある。<br /><li>キューにNSOperationのインスタンスを貯めて置いて、順番に処理を起動していく。<br /><li>並列は、1つの処理の完了を待たずに次の処理を起動する。(複数の別スレッドで処理される)<br /><li>非並列は、1つの処理が完全に終了するまで次の処理を起動しない。(全てメインスレッドで処理される)<br /><li>iOS4からは[[NSOperationQueue alloc] init]で初期化した場合は、並列になる。NSOperationなインスタンスのisConcurrentの値は関係なく。<br /><li>iOS4で非並列に処理させたい場合は、[NSOperation mainQueue] ってやる。<br /></ul><br /><br />注意すること。<br />並列で処理実行するときは、NSRunLoopの実行ループをループさせておいてのイベント処理が必要な場合がある(間違ってるかも)。<br />今回は必要なのでRunLoop入れてあります。<br /><br /><br />あーもう、ぐちゃぐちゃだーーー!!!<br />あとはソース見てください。<br /><br /><br />次回の内容は未定。<br /><br /><br /><br />Xcode 3.2.4 and iOS SDK 4.1 で試してる。<br />古いバージョンとか新しいバージョンのこと考えてない。<br /><br />新規プロジェクトをView-based Applicationを選択して名前をMyOperationとして作成してます。<br />新規ファイル追加で、NSOperationを継承したMyClassを作成しています。<br /><br /><pre name="code" class="c"><br />//<br />// MyOperationViewController.h<br />//<br />#import <UIKit/UIKit.h><br /><br />@interface MyOperationViewController : UIViewController {<br />}<br />@end<br /></pre><br /><pre name="code" class="c"><br />//<br />// MyOperationViewController.m<br />//<br />#import "MyOperationViewController.h"<br />#import "MyClass.h"<br /><br />@implementation MyOperationViewController<br /><br />- (void)owatayo:(MyClass *)obj<br />{<br /> //NSLog(@"%@", obj);<br /> //NSLog(@"no.%d", [[(MyClass *)[obj object] number] intValue]);<br /> NSNumber *num = [[obj userInfo] objectForKey:@"number"];<br /> NSLog(@"[no.%d] メインスレッド:通知owataを受け取ってowatayoメソッドを実行したよ。", [num intValue]);<br />}<br /><br />- (void)viewDidLoad<br />{<br /> [super viewDidLoad];<br /><br /> // 読み込むフィード<br /> NSString *feedURL1 = @"http://eyesrobe.blogspot.com/feeds/posts/default?alt=rss";<br /> NSString *feedURL2 = @"http://blog.eyesrobe.com/feed/rss";<br /> NSArray *feeds = [NSArray arrayWithObjects:feedURL1, feedURL2, feedURL1, feedURL2, feedURL1, feedURL2, feedURL1, feedURL2, nil];<br /> <br /> // 通知<br /> NSNotificationCenter *center = [NSNotificationCenter defaultCenter];<br /><br /> // キューの初期化<br /> NSOperationQueue *queue = [[NSOperationQueue alloc] init];<br /><br /> // NSOperationQueue に許す同時接続スレッドの数<br /> // スレッド数を制限した場合としない場合の実行内容を比較してみるといいかも。<br /> [queue setMaxConcurrentOperationCount:3];<br /><br /> // キューにNSOperationなオブジェクトを追加する。<br /> // 追加されたオブジェクは別スレッドで順に処理されていく。<br /> int i=0;<br /> for (NSString *feedURL in feeds) {<br /><br /> NSURLRequest *requestURL = [NSURLRequest requestWithURL:[NSURL URLWithString:feedURL]];<br /> MyClass *obj = [[MyClass alloc] initWithRequest:requestURL];<br /> obj.number = [NSNumber numberWithInt:(++i)];<br /> [center addObserver:self selector:@selector(owatayo:) name:@"owata" object:obj];<br /> [queue addOperation:obj];<br /> [obj release];<br /> }<br /><br /> // キューが全て処理されるまで待つメソッド<br /> // [queue waitUntilAllOperationsAreFinished];<br /> //<br /> // 待たないで処理をバックグラウンドで処理するのであれば、NSNotificationCenterなど<br /> // を使ってバックグラウンド処理完了の通知を受け取ることが多いみたい。<br /> <br /> [queue release];<br />}<br /><br />- (void)didReceiveMemoryWarning {<br /> [super didReceiveMemoryWarning];<br />}<br /><br />- (void)viewDidUnload {<br />}<br /><br />- (void)dealloc {<br /> [super dealloc];<br />}<br /><br />@end<br /></pre><br /><pre name="code" class="c"><br />//<br />// MyClass.h<br />//<br />#import <Foundation/Foundation.h><br /><br />@interface MyClass : NSOperation {<br /> NSNumber *number;<br /> NSURLRequest *requestURL;<br /><br /> BOOL done;<br />}<br /><br />@property (nonatomic, retain) NSNumber *number;<br />@property (nonatomic, retain) NSURLRequest *requestURL;<br /><br />- (id)initWithRequest:(NSURLRequest *)requestURL_;<br /><br />@end<br /></pre><br /><pre name="code" class="c"><br />//<br />// MyClass.m<br />//<br />#import "MyClass.h"<br /><br />@implementation MyClass<br /><br />@synthesize number;<br />@synthesize requestURL;<br /><br />/**<br /> * 初期化<br /> */<br />- (id)initWithRequest:(NSURLRequest *)requestURL_<br />{<br /> self = [super init];<br /> if (self != nil) {<br /> self.requestURL = requestURL_;<br /> }<br /> <br /> return self;<br />}<br /><br />/**<br /> * キューに追加されることで実行されるメソッド<br /> */<br />- (void)main<br />{<br /> NSLog(@"[No.%d] MyClass::main", [self.number intValue]);<br /><br /> // NSURLConnection<br /> NSURLConnection *urlConnection = [[[NSURLConnection alloc] initWithRequest:self.requestURL delegate:self] autorelease];<br /><br /> if (urlConnection == nil) {<br /> NSLog(@"error");<br /> }<br /> else {<br /> // データ受信完了フラグ<br /> done = NO;<br /> <br /> // NSOperationQueueで別のスレッド動かす場合、NSAutoreleasePoolは要らないみたいだけど、NSRunLoop(実行ループ?)は必要っぽい。<br /> // 処理実行中(done==NO)の間は、実行ループをループさせ続けることが必要。<br /> // ここでは、NSURLConnectionによるデータ受信完了時点で処理完了(done=YES)としている。<br /> do {<br /> [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];<br /> } while (!done);<br /> }<br /><br /> // 通知するときに一緒に送りたいメッセージ<br /> NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:number, @"number", @"value", @"key", nil];<br /><br /> // 処理が終わったら通知メッセージを送る。<br /> // メインスレッドで実行させたいので performSelectorOnMainThread:withObject:waitUntilDone: を使った。<br /> NSNotification *notification = [NSNotification notificationWithName:@"owata" object:self userInfo:dict];<br /> NSNotificationCenter *center = [NSNotificationCenter defaultCenter];<br /> [center performSelectorOnMainThread:@selector(postNotification:) withObject:notification waitUntilDone:NO];<br />}<br /><br />/**<br /> * データ受信<br /> */<br />- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {<br /> NSLog(@"[No.%d] 受信中(データは分割されて受信される)", [self.number intValue]);<br />}<br /><br />/**<br /> * 受信完了<br /> */<br />- (void)connectionDidFinishLoading:(NSURLConnection *)connection {<br /> NSLog(@"[No.%d] 受信完了", [self.number intValue]);<br /> done = YES;<br />}<br /><br />/**<br /> * 受信エラー<br /> */<br />- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {<br /> NSLog(@"エラー");<br />}<br /><br />/**<br /> * dealloc<br /> */<br />- (void)dealloc {<br /> [number release];<br /> [requestURL release];<br /> [super dealloc];<br />}<br /><br />@end<br /></pre><br /><br />たぶん続く。eyesrobehttp://www.blogger.com/profile/04737958288797616975noreply@blogger.com0tag:blogger.com,1999:blog-6897351986059227382.post-9419367080482038262010-10-29T00:09:00.002+09:002010-10-29T00:21:47.401+09:00Objective-C + libxml2 を使ってフィードを取り込みたいんだ(8)続きに何を書けばいいのかわからなくなった。<br /><br />NSOperationQueue + NSOperation を使って並列に複数フィードの読み込みをやってみればいいのか。<br />通知のこと調べたりスレッドセーフのこと調べてたりしてるうちに、お腹いっぱいになっちゃった。<br /><br />次に書く内容のポイント<br />・NSOperationQueueとNSOperation<br />・NSNotificationとNSNotificationCenter<br /><br />あとは何だろう。今日はここまで。<br /><br />続く。eyesrobehttp://www.blogger.com/profile/04737958288797616975noreply@blogger.com0tag:blogger.com,1999:blog-6897351986059227382.post-75146948901411057632010-10-27T16:05:00.002+09:002010-11-10T14:06:24.396+09:00「Cocoa Notification (NSNotification,NSNotificationCenter)」と「キー値監視」(5)少し時間があいたけど放置せずに続き書く。<br />前回まではNSNotificationCenterを使った通知の説明だったと思うので、次にキー値監視(Key-Value Observing)(略はKVO)に行く。<br /><br />調べてて物凄く混乱したりして、今も混乱中ではあるけど気にしない。<br />混乱していた最大の原因は、キー値コーディング(Key-Value Coding)(略はKVC)の知識なしにKVOを調べようとしていたこと。<br />KVCありきのKVOです。<br /><br />で、キー値コーディングってどんなのってことになるけど、自分が現状理解している範囲で説明するとする。<br />プロパティとかインスタンス変数の扱い方で、それらの名前(文字列)をキーにして値の出し入れをできるようする手段。って感じのよう。<br />注意点は、アクセサがあればアクセサを経由で値を扱ってくれて、アクセサがなければないで勝手に値の出し入れをやってくれる。<br />キー値監視のサンプルコードなどを見てると、キー値監視用のプロパティに対するアクセサがあったりなかったりなので、自分混乱しまくりでした。<br /><br />キー値監視については、指定したプロパティなどの値が変化したら通知してくれる。<br />キー値監視のサンプルコード見ててもう一つ混乱したのが、プロパティの値の変更はキー値コーディング的に行われてる場合と普通のセッター使って行われてる場合があるっぽいこと。<br /><br /><br />それと、一つ前の記事『非同期処理と通知とスレッドセーフ』でも書いたけど、バックグラウンド処理とキー値監視を組み合わせてる場合にはスレッドセーフかどうかを気にしましょう。<br />プロパティの値の変更(オブザーバへ通知)からオブザーバでの通知受取後の処理までの一連の処理は、通知元のスレッドIDで実行されてたりします。<br /><br />疲れたのでサンプル載せて「キー値監視」のことはもう終わりにしちゃう。<br />ハッキリ言って、「キー値コーディング」「キー値監視」は奥が深そうです。<br />こんなわたしのブログ見るよりまともな参考書で勉強すべきだ、とういうのが今回の結論です。<br /><br /><br />ここで『「Cocoa Notification (NSNotification,NSNotificationCenter)」と「キー値監視」』について終わり。<br />混乱は収束しないです。<br /><br /><br />Xcode 3.2.4 and iOS SDK 4.1 で試してる。<br />古いバージョンとか新しいバージョンのこと考えてない。<br /><br />新規プロジェクトをView-based Applicationを選択して名前をMyKvoとして作成してます。<br />新規ファイル追加で、NSObjectを継承したcreatureを作成しています。<br /><pre name="code" class="c"><br />// MyKvoViewController.h<br /><br />#import <UIKit/UIKit.h><br /><br />@class creature;<br /><br />@interface MyKvoViewController : UIViewController {<br /> creature *human;<br />}<br /><br />@property (nonatomic, retain) creature *human;<br /><br />@end<br /></pre><br /><pre name="code" class="c"><br />// MyKvoViewController.m<br /><br />#import "MyKvoViewController.h"<br />#import "creature.h"<br /><br />@implementation MyKvoViewController<br /><br />@synthesize human;<br /><br />- (void)viewDidLoad {<br /> [super viewDidLoad];<br /><br /> human = [[creature alloc] init];<br /> human.sex = @"male";<br /><br /> // humanオブジェクトのcommentプロパティの値に変化があれば selfに通知されるようにする。<br /> // ここではselfがオブザーバとなる。<br /> [human addObserver:self forKeyPath:@"comment" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:NULL];<br /><br /> // いろいろな方法でhumanのcommentプロパティの値を変化させてみよう。<br /> human.comment = @"I am a man.";<br /> [human setComment:@"I'm a male."];<br /> [human setValue:@"I'm not sure." forKey:@"comment"];<br /> [human setIsHavingSausage:YES];<br /> [human setIsHavingSausage:NO];<br /> <br /> // commentのキー値変更のselfに対する通知を停止する。<br /> // addObserver に対して removeObserver。使わなくなったキー値監視は消すように。<br /> [human removeObserver:self forKeyPath:@"comment"];<br /> human.comment = @"I am a man.";<br />}<br /><br />/**<br /> * ここで通知を受けとる<br /> */<br />- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context<br />{<br /> if ([keyPath isEqual:@"comment"]) {<br /> NSLog(@"通知受信 comment:%@", [(creature *)object comment]);<br /> }<br />}<br /><br />- (void)didReceiveMemoryWarning {<br /> [super didReceiveMemoryWarning];<br />}<br /><br />- (void)viewDidUnload {<br />}<br /><br />- (void)dealloc {<br /> [human release];<br /> [super dealloc];<br />}<br /><br />@end<br /></pre><br /><pre name="code" class="c"><br />// creature.h<br /><br />#import <Foundation/Foundation.h><br /><br />@interface creature : NSObject {<br /> NSString *comment;<br /> NSString *sex;<br /> BOOL isHavingSausage;<br />}<br /><br />@property (nonatomic, retain) NSString *comment;<br />@property (nonatomic, retain) NSString *sex;<br /><br />- (void)setIsHavingSausage:(BOOL)isHavingSausage_;<br /><br />@end<br /></pre><br /><pre name="code" class="c"><br />// creature.m<br /><br />#import "creature.h"<br /><br />@implementation creature<br /><br />@synthesize comment;<br />@synthesize sex;<br /><br />- (void)setIsHavingSausage:(BOOL)isHavingSausage_<br />{<br /> if (isHavingSausage_ && [self.sex isEqualToString:@"male"]) {<br /> self.comment = @"I am a real man.";<br /> } else {<br /> self.comment= @"I'm a woman!";<br /> }<br /> <br /> isHavingSausage = isHavingSausage_;<br />}<br /><br />- (void)dealloc {<br /> [comment release];<br /> [sex release];<br /> [super dealloc];<br />}<br /><br />@end<br /></pre><br /><br /><br />続かない。eyesrobehttp://www.blogger.com/profile/04737958288797616975noreply@blogger.com0tag:blogger.com,1999:blog-6897351986059227382.post-56120132941598256852010-10-20T15:44:00.006+09:002010-10-26T15:54:40.914+09:00非同期処理と通知とスレッドセーフNSOperationQueue と KVO ( Key-Value Observing )を組み合わせればスレッドセーフかどうかを気にしなくていで実装できるのかも、と期待してみたが違うようだ。<br /><br />監視と通知は、それぞれのオブジェクトのスレッドで行われるらしい。<br /><br />NSOperationQueue と NSNotificationCenter と NSObjectの performSelectorOnMainThread:withObject:waitUntilDone: の組み合わせが良さそう。<br /><br /><blockquote><br />KVO しているプロパティがバックグラウンドスレッドで変更されたら、オブザーバのメソッドも同じバックグラウンドスレッドで呼び出されます。<br />「<a href="http://dev.elegant-apps.com/blog/archives/2010/09/13/uikit-and-thread.html">UIKit とスレッドのお約束 - Elegant Apps Developers</a>」<br /></blockquote><br /><br /><br /><br />2010-10-26 追記:それと、KVO じゃなくて NSOperation の話になるけれども以下のことを付け足しておく。<br /><br />メインスレッドから [queue cancelAllOperations] などとして、別スレッドでバックグラウンド実行中処理の [myOperation cancel] が発動されると、[myOperation cancel] はメインスレッドで実行される。そんでそのバックグラウンド実行中のものは別スレッドでそのまま動いているから、どっちがどっちって感じになってしまうと。<br /><br />キャンセル>即処理終了、ってことではないから、isCancelled とか使ってキャンセルされるときのことも考えて書いていこうね。ってことで。eyesrobehttp://www.blogger.com/profile/04737958288797616975noreply@blogger.com0tag:blogger.com,1999:blog-6897351986059227382.post-71745123060188926432010-10-19T17:45:00.004+09:002010-10-19T17:54:41.570+09:00「Cocoa Notification (NSNotification,NSNotificationCenter)」と「キー値監視」(4)前回の記事も何となく説明の仕方が間違ってるような気がする。<br />サンプルのコードが悪いのか、それともそもそも根本的に間違っているのか。<br /><br />とりあえず、サンプルのコードを書き直してみた。<br /><br />新規プロジェクトをView-based Applicationを選択して名前をMyNotificationとして作成してます。<br />新規ファイル追加で、NSObjectを継承したMyNotificationを作成しています。<br /><br />「Cocoa Notification (NSNotification,NSNotificationCenter)」を試しなおす。<br />説明できることはほとんど前回までと変わらないのでサンプルコードだけ載せる。<br /><br /><pre name="code" class="c"><br />// MyNotificationViewController.h<br /><br />#import <UIKit/UIKit.h><br /><br />@interface MyNotificationViewController : UIViewController {<br /> NSInteger count;<br /> NSTimer *timer;<br />}<br /><br />@end<br /></pre><br /><pre name="code" class="c"><br />// MyNotificationViewController.m<br /><br />#import "MyNotificationViewController.h"<br />#import "MyNotification.h"<br /><br />@implementation MyNotificationViewController<br /><br />/**<br /> * 新しくスレッドをたてて、myNotificationのmyWorkメソッドを実行する。<br /> */<br />- (void)newThread<br />{<br /> count++;<br /> <br /> MyNotification *myNotification = [[[MyNotification alloc] init] autorelease];<br /> [NSThread detachNewThreadSelector:@selector(myWork:) toTarget:myNotification withObject:[NSString stringWithFormat:@"%d",count]];<br /><br /> if(count > 2) {<br /> [timer invalidate];<br /> timer = nil;<br /> }<br />}<br /><br />/**<br /> * 通知受け取ったときに呼ばれる処理<br /> */<br />- (void)owatayo:(id)info<br />{<br /> NSDictionary *userInfo = (NSDictionary *)[info userInfo];<br /> NSLog(@"メインスレッド:(no.%@スレッドから)通知owataを受け取りowatayoメソッドを実行。", [userInfo objectForKey:@"threadCount"]);<br />}<br /><br />- (void)viewDidLoad<br />{<br /> [super viewDidLoad];<br /><br /> NSLog(@"メインスレッド:処理開始");<br /> <br /> // NSNotificationCenterのインスタンスに、<br /> // addObserver : 通知を受け取るオブジェクト(ここでは自分自身)<br /> // selector : 通知を受けたときに実行するメソッド<br /> // name : 通知される通知名<br /> // object : どのオブジェクトからの通知を受け取るのか指定できる。nilであれば限定しない。<br /> NSNotificationCenter *center;<br /> center = [NSNotificationCenter defaultCenter];<br /> [center addObserver:self selector:@selector(owatayo:) name:@"owata" object:nil];<br /> <br /><br /> NSLog(@"新スレッドを0.5秒間隔で作成します。");<br /> count = 0;<br /> timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(newThread) userInfo:nil repeats:YES];<br /><br /> NSLog(@"メインスレッド:処理終了");<br />}<br /><br />- (void)didReceiveMemoryWarning {<br /> [super didReceiveMemoryWarning];<br />}<br /><br />- (void)viewDidUnload {<br />}<br /><br />- (void)dealloc {<br /> [super dealloc];<br />}<br /><br />@end<br /></pre><br /><pre name="code" class="c"><br />// MyNotification.h<br /><br />#import <Foundation/Foundation.h><br /><br />@interface MyNotification : NSObject {<br />}<br /><br />- (void)myWork:(NSString *)num;<br />- (void)didMyWork:(NSString *)threadCount;<br /><br />@end<br /></pre><br /><pre name="code" class="c"><br />// MyNotification.m<br /><br />#import "MyNotification.h"<br /><br />@implementation MyNotification<br /><br />/*<br /> * 新スレッドでの処理<br /> */<br />- (void)myWork:(NSString *)threadCount<br />{<br /> NSLog(@"(no.%@)新スレッドの処理開始", threadCount);<br /><br /> NSAutoreleasePool *pool;<br /> pool = [[NSAutoreleasePool alloc] init];<br /> [NSThread sleepForTimeInterval:3.0];<br /> [self didMyWork:threadCount];<br /> [NSThread sleepForTimeInterval:3.0];<br /> [pool release];<br /><br /> NSLog(@"(no.%@)スレッド破棄", threadCount);<br /> [NSThread exit];<br />}<br /><br />/*<br /> * 新スレッド終了するときの通知させる処理<br /> */<br />- (void)didMyWork:(NSString *)threadCount<br />{<br /> NSDictionary *myInfo = [NSDictionary dictionaryWithObjectsAndKeys:threadCount, @"threadCount", nil];<br /><br /> // 通知する内容を指定<br /> NSNotification *notification;<br /> notification = [NSNotification notificationWithName:@"owata" object:self userInfo:myInfo]; <br /><br /> // 通知する(メインスレッドから通知する)<br /> NSNotificationCenter *center= [NSNotificationCenter defaultCenter];<br /> [center performSelectorOnMainThread:@selector(postNotification:) withObject:notification waitUntilDone:NO];<br />}<br /><br />@end<br /></pre>eyesrobehttp://www.blogger.com/profile/04737958288797616975noreply@blogger.com0tag:blogger.com,1999:blog-6897351986059227382.post-85805210161516831442010-10-18T12:08:00.005+09:002010-11-10T14:06:54.247+09:00「Cocoa Notification (NSNotification,NSNotificationCenter)」と「キー値監視」(3)新しいスレッドを立ててそのスレッドから「通知」をそのまま送ると「スレッド・セーフでない」ので、セレクター使ってちゃんとメインスレッドのNSNotificationCenterから「通知」されるように書く必要あり。<br /><br /><br />前回からの続き。<br />前回のを実行したときのログが以下のように出力されたけど、気になる点が下から2行目。<br /><br />ログの[470:5c03]は[プロセスID:スレッドID]として現れている。<br />わたしは、この下から2行目の処理がメインスレッドで実行されることを期待していたのだけれど、スレッドIDを見ると何故かしら新スレッドのIDで実行されているのがわかる。<br /><pre><br />2010-10-18 11:03:50.584 MyNotification[470:207] メインスレッド:処理開始<br />2010-10-18 11:03:50.589 MyNotification[470:5c03] 新スレッド:処理開始<br />2010-10-18 11:03:50.589 MyNotification[470:207] メインスレッド:処理終了<br />2010-10-18 11:03:51.593 MyNotification[470:5c03] 新スレッド:0<br />2010-10-18 11:03:52.596 MyNotification[470:5c03] 新スレッド:1<br />2010-10-18 11:03:53.599 MyNotification[470:5c03] 新スレッド:2<br />2010-10-18 11:03:54.602 MyNotification[470:5c03] 新スレッド:3<br />2010-10-18 11:03:55.605 MyNotification[470:5c03] 新スレッド:4<br />2010-10-18 11:03:55.608 MyNotification[470:5c03] 新スレッド:通知を送るよ。通知の名前はowataだよ。<br />2010-10-18 11:03:55.615 MyNotification<em style="color:red">[470:5c03] メインスレッド:</em>通知owataを受け取ってowatayoメソッドを実行したよ。<br />2010-10-18 11:03:55.619 MyNotification[470:5c03] 新スレッド:処理終了<br /></pre><br />で、少し調べてみたところ、これは「スレッドセーフでない」状態ということらしい。<br />「<a href="http://d.hatena.ne.jp/KishikawaKatsumi/20100115/1263544396">メインスレッド以外のスレッドから NSNotification で通知する場合 - 24/7 twenty-four seven</a>」<br /><br />で、もう少し調べてみると、<br />セレクターを渡すことでメインスレッドのpostNotification:を実行させる方法があるようなので、そっちを試してみた。<br />前回書いた部分の以下のコードを変更する。<br /><pre name="code" class="c"><br />/*<br /> * 新スレッド終了するときの通知させる処理<br /> */<br />- (void)didMyWork<br />{<br /> NSNotification *notification;<br /> notification = [NSNotification notificationWithName:@"owata" object:self userInfo:nil];<br /> <br /> NSLog(@"新スレッド:通知を送るよ。通知の名前はowataだよ。");<br /> NSNotificationCenter *center;<br /> center = [NSNotificationCenter defaultCenter];<br /><br /> // これだと、<br /> // [center postNotification:notification];<br /> // 新スレッドで「通知」されるので、<br /> // <br /> // performSelectorOnMainThread:withObject:waitUntilDone:<br /> // こっちでメインスレッドから「通知」されるようにする <br /> // <br /> [center performSelectorOnMainThread:@selector(postNotification:) withObject:notification waitUntilDone:NO];<br />}<br /></pre><br /><pre><br />2010-10-18 11:06:50.287 MyNotification[531:207] メインスレッド:処理開始<br />2010-10-18 11:06:50.289 MyNotification[531:5c03] 新スレッド:処理開始<br />2010-10-18 11:06:50.290 MyNotification[531:207] メインスレッド:処理終了<br />2010-10-18 11:06:51.291 MyNotification[531:5c03] 新スレッド:0<br />2010-10-18 11:06:52.292 MyNotification[531:5c03] 新スレッド:1<br />2010-10-18 11:06:53.293 MyNotification[531:5c03] 新スレッド:2<br />2010-10-18 11:06:54.295 MyNotification[531:5c03] 新スレッド:3<br />2010-10-18 11:06:55.296 MyNotification[531:5c03] 新スレッド:4<br />2010-10-18 11:06:55.297 MyNotification[531:5c03] 新スレッド:通知を送るよ。通知の名前はowataだよ。<br />2010-10-18 11:06:55.299 <em style="color:red">MyNotification[531:207] メインスレッド:</em>通知owataを受け取ってowatayoメソッドを実行したよ。<br />2010-10-18 11:06:55.300 MyNotification[531:5c03] 新スレッド:処理終了<br /></pre><br />これでオッケーな感じかな。<br /><br /><br />追記:何となく変な感じがするので次回、サンプルのコードを書き直す。eyesrobehttp://www.blogger.com/profile/04737958288797616975noreply@blogger.com0tag:blogger.com,1999:blog-6897351986059227382.post-10832624514072337722010-10-15T19:19:00.002+09:002010-10-18T11:37:05.673+09:00「Cocoa Notification (NSNotification,NSNotificationCenter)」と「キー値監視」(2)「Cocoa Notification (NSNotification,NSNotificationCenter)」を実際に試してみることにする。<br /><br />新規プロジェクトをView-based Applicationを選択して名前をMyNotificationとして作成してます。<br /><br />新規ファイル追加で、NSObjectを継承したMyNotificationを作成しています。<br /><br />以下、編集したファイルの中身です。<br />なるべく簡潔に分かりやすくを心がけたつもり。<br /><br /><br /><pre name="code" class="c"><br />// MyNotificationViewController.h<br /><br />#import <UIKit/UIKit.h><br /><br />@interface MyNotificationViewController : UIViewController {<br />}<br /><br />@end<br /></pre><br /><br /><pre name="code" class="c"><br />// MyNotificationViewController.m<br /><br />#import "MyNotificationViewController.h"<br />#import "MyNotification.h"<br /><br />@implementation MyNotificationViewController<br /><br />/*<br /> * 通知受け取ったときに呼ばれる処理<br /> */<br />- (void)owatayo<br />{<br /> NSLog(@"メインスレッド:通知owataを受け取ってowatayoメソッドを実行したよ。");<br />}<br /><br />- (void)viewDidLoad<br />{<br /> [super viewDidLoad];<br /><br /> NSLog(@"メインスレッド:処理開始");<br /><br /> // ここでは、通知を受けるObserverをselfとし、通知するSubjectをmyNotificationとする。<br /> // 新しいスレッドをたて、その新スレッドからの通知を受け取れることの確認によって「監視」のテストとする。<br /> MyNotification *myNotification = [[[MyNotification alloc] init] autorelease];<br /> <br /> // NSNotificationCenterのインスタンスに、<br /> // addObserver : 通知を受け取るオブジェクト(ここでは自分自身)<br /> // selector : 通知を受けたときに実行するメソッド<br /> // name : 通知される通知名<br /> // object : どのオブジェクトからの通知を受け取るのか指定できる。nilであれば限定しない。<br /> NSNotificationCenter *center;<br /> center = [NSNotificationCenter defaultCenter];<br /> [center addObserver:self selector:@selector(owatayo) name:@"owata" object:myNotification];<br /> <br /> // 新しいスレッドをたて、myNotificationのmyWorkメソッドを実行する。<br /> [NSThread detachNewThreadSelector:@selector(myWork) toTarget:myNotification withObject:nil];<br /><br /> NSLog(@"メインスレッド:処理終了");<br />}<br /><br />- (void)didReceiveMemoryWarning {<br /> [super didReceiveMemoryWarning];<br />}<br /><br />- (void)viewDidUnload {<br />}<br /><br />- (void)dealloc {<br /> [super dealloc];<br />}<br /><br />@end<br /></pre><br /><br /><pre name="code" class="c"><br /><br />// MyNotification.h<br /><br />#import <Foundation/Foundation.h><br /><br />@interface MyNotification : NSObject {<br />}<br /><br />- (void)myWork;<br />- (void)didMyWork;<br /><br />@end<br /></pre><br /><br /><pre name="code" class="c"><br />// MyNotification.m<br /><br />#import "MyNotification.h"<br /><br />@implementation MyNotification<br /><br />/*<br /> * 新スレッドでの処理<br /> */<br />- (void)myWork<br />{<br /> NSLog(@"新スレッド:処理開始");<br /> NSAutoreleasePool *pool;<br /> pool = [[NSAutoreleasePool alloc] init];<br /> <br /> for (int i=0; i<5; i++) {<br /> [NSThread sleepForTimeInterval:1.0];<br /> NSLog(@"新スレッド:%d", i);<br /> }<br /> <br /> [self didMyWork];<br /> [pool release];<br /> NSLog(@"新スレッド:処理終了");<br /> [NSThread exit];<br />}<br /><br />/*<br /> * 新スレッド終了するときの通知させる処理<br /> */<br />- (void)didMyWork<br />{<br /> // 通知を受け取る側では以下のようにobserverをNSNotificationCenterに追加している。<br /> // NSNotificationCenter *center;<br /> // center = [NSNotificationCenter defaultCenter];<br /> //[center addObserver:self selector:@selector(owatayo) name:@"owata" object:myNotification];<br /> // <br /> // name:@"owata" と notificationWithName:@"owata" で指定している @"owata" をキーとして通知のやりとりを行う。<br /> // 後は、NSNotification の postNotification: で通知を送れば、勝手に通知を受け取ってくれる。<br /> NSNotification *notification;<br /> notification = [NSNotification notificationWithName:@"owata" object:self userInfo:nil];<br /> <br /> NSLog(@"新スレッド:通知を送るよ。通知の名前はowataだよ。");<br /> NSNotificationCenter *center;<br /> center = [NSNotificationCenter defaultCenter];<br /> [center postNotification:notification];<br />}<br /><br />@end<br /></pre><br />こんな感じにログがでるはず。<br /><pre><br />2010-10-15 18:51:43.333 MyNotification[2310:207] メインスレッド:処理開始<br />2010-10-15 18:51:43.336 MyNotification[2310:5c03] 新スレッド:処理開始<br />2010-10-15 18:51:43.336 MyNotification[2310:207] メインスレッド:処理終了<br />2010-10-15 18:51:44.337 MyNotification[2310:5c03] 新スレッド:0<br />2010-10-15 18:51:45.338 MyNotification[2310:5c03] 新スレッド:1<br />2010-10-15 18:51:46.339 MyNotification[2310:5c03] 新スレッド:2<br />2010-10-15 18:51:47.341 MyNotification[2310:5c03] 新スレッド:3<br />2010-10-15 18:51:48.342 MyNotification[2310:5c03] 新スレッド:4<br />2010-10-15 18:51:48.343 MyNotification[2310:5c03] 新スレッド:通知を送るよ。通知の名前はowataだよ。<br />2010-10-15 18:51:48.344 MyNotification<em style="color:red">[2310:5c03] メインスレッド:</em>通知owataを受け取ってowatayoメソッドを実行したよ。<br />2010-10-15 18:51:48.345 MyNotification[2310:5c03] 新スレッド:処理終了<br /></pre><br /><br /><em style="color:red">追記:赤文字の部分にちょっと注意が必要そうなので、次の記事でそのこと書く。今回書いたサンプルコードではスレッド・セーフになってなさそう。</em><br /><br />あれ?もしかして、NSNotification と NSNotificationCenter 使うと超簡単だったりするんじゃないの?<br /><br />続く。eyesrobehttp://www.blogger.com/profile/04737958288797616975noreply@blogger.com0tag:blogger.com,1999:blog-6897351986059227382.post-88795865530833758672010-10-15T17:27:00.003+09:002010-10-15T17:37:32.802+09:00「Cocoa Notification (NSNotification,NSNotificationCenter)」と「キー値監視」(1)Observerパターン<br /><br />『<a href="http://journal.mycom.co.jp/column/objc/109/index.html">ダイナミックObjective-C「デザインパターンをObjective-Cで - Observer (1)」</a>』<br />『<a href="http://journal.mycom.co.jp/column/objc/110/index.html">ダイナミックObjective-C「デザインパターンをObjective-Cで - Observer (2)」</a>』<br />『<a href="http://journal.mycom.co.jp/column/objc/111/index.html">ダイナミックObjective-C「デザインパターンをObjective-Cで - Observer (3)」</a>』<br /><br />今回書く内容は、上の記事を参考にして「Cocoa Notification」と「キー値監視」による「監視」についてのことを自分なりに噛み砕いて適当に書いている。間違ってたらごめんなさい。<br /><br />Observerパターンは、「監視」のためのパターンだそうです。<br />あるオブジェクトを監視して、そのオブジェクトに何らかの状態変化が起きたとき、変化が起こったことを知らせる。<br /><br />「Cocoa Notification」と「キー値監視」は、その「監視」のための方法です。<br /><br /><br />Observer = オブザーバー、監視者<br /><br /><br />Observerパターンに登場するクラスは2つで、監視するクラスと監視されて通知を行うクラスだ。<br /><ul><li>監視するクラスの方がObserverクラス<br /><li>監視されるクラスの方がSubjectクラス<br /></ul><br />例えば、データが更新される毎にグラフの表示が変わるような処理がある場合、<br /><ul><li>グラフ表示が、Observerとしてデータの変化を「監視する」<br /><li>データ自体が、Subjectとして「監視される」側となり変化が起きたら「通知する」<br /></ul><br />例えば無理やり、あなた(Subject)とあなたの上司(Observer)として考えてみるとすると、<br /><ul><li>上司は、Observerとして部下の管理をする。<br /><li>あなたは、Subjectとしてなにかあったら上司に報告する。<br /></ul><br />具体的には、<br /><ul><li>あなたは与えられた仕事が完了したので、終わったことを上司に報告する。<br /><li>あなたは体調が悪くなったので、早退したいことを上司に報告する。<br /></ul><br />みたいな。<br /><br />いや~わかりにくいなぁ。<br /><br /><br /><br />「監視者」がいて、監視される人として「あなた」がいる場合、「監視」として正しいのはどれ?<br /><ol><li>「監視者」が「あなた」の状態変化を「監視」し「通知」する。<br /><li>「あなた」の状態が変化したら、「あなた」は「監視者」に「通知」する。<br /><li>「あなた」の状態が変化したら、「通知」という方法で「監視者」に気づいてもらう。<br /></ol><br />正解は、<br /><ol><li>× これは正しいように見えるけど、ちょっと違う。「監視者」が「監視」し「通知」もしてるのが違う。そもそも実は「監視者」は「監視」しない。「あなた」が「通知」する。<br /><li>◯ これ正解。<br /><li>◯ これも雰囲気はあってるかな。<br /></ol><br /><br />混乱するね。<br />じゃぁ「監視」ってあるけど誰が監視してんの?ってことになるんだけど、結局は誰も監視してないんだよね。<br /><br />だから「通知」を主として考えると、<br /><ul><li>通知を受け取るクラスをObserverクラス<br /><li>通知をするクラスをSubjectクラス<br /></ul><br />って感じに頭で整理しちゃってもいいんじゃないかなとも思うんだけど。ダメかな。<br /><br /><br /><br />「NSNotification + NSNotificationCenter」のこと<br /><ul><li>NSNotificationCenterのインスタンスは1つしかない。<br /><li>NSNotificationCenterのインスタンスは1つしかないので、扱い方がシンプルであまり迷わなさそう。<br /><li>1つしかないNSNotificationCenterのインスタンスを使って、ObserverとSubjectをゆるーい感じで繋げて「監視」対応ができるようになっている。<br /><li>「通知」する側も「通知」を受け取る側も、1つしかないNSNotificationCenterのインスタンスを一緒になかよく使う感じで。<br /></ul><br /><br />「キー値監視」のこと<br /><ul><li>「キー値監視」はNSObjectのレベルで実装されている。<br /><li>NSNotificationと比べた場合、「監視者」が「通知」を受けた後に実行するメソッドを指定することが出来ない。<br /><li>キー値コーディングのsetValue:forKey:というメソッドで「通知」しているので、特に何もしなくとも自動的に通知が行われているように感じられる。これは、通知の乱発につながる場合があるらくい。<br /><li>その実際は、自分でアクセサメソッドを実装してその中で手動での制御が必要になるかもしれない。<br /></ul><br /><br />あーダメだ。ちゃんと理解できてないないない。<br />ない。<br /><br />続く。eyesrobehttp://www.blogger.com/profile/04737958288797616975noreply@blogger.com0tag:blogger.com,1999:blog-6897351986059227382.post-80040390103016792082010-10-14T23:44:00.004+09:002010-10-14T23:52:02.948+09:00NSFetechedResultsController は使わなくてもいいけど、NSFetechedResultsController を使うと、SQLiteのデータ取得とデータ取得後の情報の取り扱いをいい感じにコントロールできるようになる。<br /><br />らしい。eyesrobehttp://www.blogger.com/profile/04737958288797616975noreply@blogger.com0tag:blogger.com,1999:blog-6897351986059227382.post-11102956994614604352010-10-14T16:03:00.002+09:002010-11-10T14:06:42.803+09:00Objective-C + libxml2 を使ってフィードを取り込みたいんだ(7)前々回からの続き。<br /><br />NSURLConnection で非同期でフィードを勝手に読み込んでくれるのは助かるよ。<br />けど、NSURLConnection で非同期処理をほぼ同時期にいっぱい開くのはどうだろうか。<br />良くなくなくないってことで対応しようと思う。<br /><br /><br />ここで、libxml2 のことでなくて NSOperation の話に変わって行くことになるらしい。<br />気にせず進める。<br /><br />調べてたらNSOperation使うのは、裏で複数の処理を動かしたいんだったら、行儀よくスレッド分けて動かしたほうがいいんじゃないか。ってことっぽい。<br /><br /><br /><br />しかし難しい。いろいろと調べてて混乱が深まるばかりだ。<br />いま混乱しているのは通知のところ。<br />NSOperationQueueのキューに突っ込んだNSOperation なインスタンスは、メインスレッドからは切り離されて処理されてるけど、処理が終了したときはメインスレッドに「終わったよ」ってお知らせしてね。これが通知。<br />で、混乱してるのは通知する方法が2つあるっぽいってこと。<br /><br />1.キー値監視<br />2.Cocoa Notification<br /><br />NSOperation のことをあっちこっち見ながら調べてると、キー値監視でやってることが多い。<br />AppleのサンプルのTopSongsだとNotification使ってる。<br /><br /><br />どうするか。通知はどっちでやっていくか。<br />簡単そうなのはキー値監視する方。<br />Cocoa Notification は茨の道だけど、使えるようになると応用が効きそう。<br /><br /><br />って、両方やらないとだろ。<br />ってことで「Objective-C + libxml2 を使ってフィードを取り込みたいんだ」の続きを中断して<br /><br />・「キー値監視(key-value observing 略してKVO)を調べる」<br />・「Cocoa Notification を調べる」<br /><br />を(できれば)やっていきたい。<br /><br /><br />(そろそろ挫折するかもしれん。)eyesrobehttp://www.blogger.com/profile/04737958288797616975noreply@blogger.com0tag:blogger.com,1999:blog-6897351986059227382.post-74552077303893839382010-10-13T18:44:00.001+09:002010-10-13T18:44:38.843+09:00Objective-C + libxml2 を使ってフィードを取り込みたいんだ (6)ちょっと休憩。<br /><br />libxml2のSAXパーサか、NSXMLParserか。<br /><br />どちらもSAXパーサだけど、ダウンロードサイズが大きめのXMLだったらlibxml2を選んだ方が良いらしい。<br /><br />NSXMLParserのが実装簡単。<br /><br />やりたいことはNSXMLParserで十分賄えただろうに。<br /><br />速いに越したことはないということで。<br /><br />続くeyesrobehttp://www.blogger.com/profile/04737958288797616975noreply@blogger.com0tag:blogger.com,1999:blog-6897351986059227382.post-50386731758085481902010-10-13T18:28:00.002+09:002010-10-13T18:44:47.467+09:00Objective-C + libxml2 を使ってフィードを取り込みたいんだ (5)前回の(4)は説明不足すぎるような気がする。気が向いたら内容を見直してみる。<br /><br />とりあえずフィードを読み込むことはできるようになった。<br />作ったRSSImporterってクラスでは、指定した1つのフィードURLにアクセスしてブログの情報を持ってこれた。<br /><br /><br /><br />次は、1つだけじゃなくて複数のフィードURLを指定して情報を取得したいと思う。<br /><br />RSSImporterクラスでは、「指定した1つのフィードURLにアクセスしてブログの情報を持ってこれる。」<br />っていう作りは変更しない。<br />変更はしないけど、フィードURLをメソッド内で直接指定するのではなくて、インスタンス作るときに指定するように改良しよう。<br /><br />- (id)init を使うのやめて、 -(id)initWithRequest: を作ってこっちで初期化処理をすることにする。<br /><pre name="code" class="php"><br />// RSSImporter.h<br /><br />// これ追加<br />- (id)initWithRequest:(NSURLRequest *)requestURL;<br /></pre><br /><pre name="code" class="php"><br />// Rssimporter.m<br /><br />//<br />// これ追加<br />//<br />// - (id)init { // これ削除<br />- (id)initWithRequest:(NSURLRequest *)requestURL {<br /> <br /> self = [super init];<br /> if (self != nil) {<br /><br /> self.isBuffering = NO;<br /> self.characterBuffer = [NSMutableData data];<br /> <br /> // パーサ用のコンテクストを作る<br /> if (!context) {<br /> context = xmlCreatePushParserCtxt(&simpleSAXHandlerStruct, self, NULL, 0, NULL);<br /> }<br /> <br /><br /> // これ削除<br /> //NSString *feedURL = @"http://eyesrobe.blogspot.com/feeds/posts/default?alt=rss";<br /> //NSURLRequest *requestURL = [NSURLRequest requestWithURL:[NSURL URLWithString:feedURL]];<br /><br /> NSURLConnection *urlConnection = [[[NSURLConnection alloc] initWithRequest:requestURL delegate:self] autorelease];<br /> if (urlConnection == nil) {<br /> NSLog(@"error");<br /> }<br /> }<br /> <br /> return self;<br />}<br /></pre><br />これで、RSSImporterのインスタンスを作るときにURLを指定できるようになった。<br /><br />こんな感じで。<br /><pre name="code" class="php"><br />// {YourProject}AppDelegate.m <br /><br />@interface FooAppDelegate : NSObject <UIApplicationDelegate> {<br /> UIWindow *window;<br /> FooViewController *viewController;<br /><br /> // これ削除<br /> // RSSImporter *importer;<br />}<br /></pre><br /><pre name="code" class="php"><br />// {YourProject}AppDelegate.h <br /><br />// これ削除<br />// @synthesize importer;<br /><br /><br />- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { <br /> <br /> // これを削除<br /> // importer = [[RSSImporter alloc] init];<br /><br /> // これ追加<br /> NSString *feedURL1 = @"http://eyesrobe.blogspot.com/feeds/posts/default?alt=rss";<br /> NSString *feedURL2 = @"http://blog.eyesrobe.com/feed/rss";<br /> NSArray *feeds = [NSArray arrayWithObjects:feedURL1, feedURL2, feedURL1, feedURL2, feedURL1, feedURL2, feedURL1, feedURL2, nil];<br /> for (NSString *feedURL in feeds) {<br /><br /> NSURLRequest *requestURL = [NSURLRequest requestWithURL:[NSURL URLWithString:feedURL]];<br /> <br /> RSSImporter *importer;<br /> importer = [[RSSImporter alloc] initWithRequest:requestURL];<br /> [importer autorelease];<br /> }<br /><br /> <br /> [window addSubview:viewController.view];<br /> [window makeKeyAndVisible];<br /> return YES;<br />}<br /><br /><br />- (void)dealloc {<br /> // これ削除<br /> // [importer release];<br /> <br /> [viewController release];<br /> [window release];<br /> [super dealloc];<br />}<br /></pre><br /><br />たくさんのURLを指定するとどうなるかを見たかったので無駄にURLを指定してみた。<br />NSArray *feeds = [NSArray arrayWithObjects:feedURL1, feedURL2, feedURL1, feedURL2, feedURL1, feedURL2, feedURL1, feedURL2, nil];<br /><br />で、どうなるかというと、<br />順番に処理が開始されて、同時並行的に情報の読み込みが行われてる感じになっているっぽい。順番に開始するけど順番に終了はしなくて、読み込み終わった順に終了するってことになるっぽい。<br /><br />それで何か問題があるかどうか?<br /><br /><blockquote><br />『RSSリーダでは、複数のフィードを一度にダウンロードすることが求められる。しかし、数十個のNSURLConnectionを一気に作成したら、帯域を食いつぶしてしまうだろう。』<br /><a href="http://journal.mycom.co.jp/column/iphone/006/index.html">実践! iPhoneアプリ開発「RSSリーダの作り方 (2) - 複数のダウンロードを並行して処理する」</a>から引用<br /></blockquote><br /><br />ってことで、続く。eyesrobehttp://www.blogger.com/profile/04737958288797616975noreply@blogger.com0tag:blogger.com,1999:blog-6897351986059227382.post-81975809335773205252010-10-13T10:59:00.000+09:002010-10-13T11:00:02.750+09:00Memoha 1.2.3 と Moneyha 1.0.12010年10月7日に Memoha version 1.2.3 が無事にリリースされた。<br />2010年9月29日に Moneyha version 1.0.1 が無事にリリースされた。eyesrobehttp://www.blogger.com/profile/04737958288797616975noreply@blogger.com0