2012年2月24日金曜日

Objective-CでTweetからハッシュタグを抽出する

「直近のtweetからハッシュタグを10件抽出して候補とする」って機能を実装する為に、tweetの文字列からハッシュタグの一覧を抽出するプログラムを作りますた。

1文字ずつパースしてはいないので実行速度はあまり速くないと思います。
- (NSArray *)hashTagFromString:(NSString *)_string
{
 NSMutableArray *result = [NSMutableArray array];
 NSInteger length = [_string length];
 NSRange validRange = {0, length};
 while (YES) {
  NSRange range = [_string rangeOfString:@"(^#[^ ]+ | #[^ ]+ | #[^ ]+$|^#[^ ]+$)" options:NSRegularExpressionSearch range:validRange];
  if (range.location == NSNotFound) {
   break;
  }
  NSString *hashTag = [_string substringWithRange:range];
  NSString *trimedHashTag = [hashTag stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
  [result addObject:trimedHashTag];
  validRange.location = range.location + range.length;
  validRange.length = length - validRange.location;
 }
 
 return result;
 
}
※twitterAPIにてinclude_entities=trueをオプションしていするとハッシュタグ一覧を取得することができます。
このエントリーをはてなブックマークに追加

2012年2月22日水曜日

NSOperationのdeallocが呼ばれなくてハマりました

ひさしぶりにメモリ関連でハマりました。
NSOperationのdeallocが呼び出されなくてメモリーリークしまクリスティ。
setCompletionBlock内でoperation自身を参照したのが原因のようです。「自分で自分のリテインカウントをインクリメントして保持」てきなことが起こっているのかな?

// オペレーションがqueueから削除された時の処理設定
 [anOperation setCompletionBlock:^{
  // delegateに通知
  if (_delegate) {
   [_delegate netWorkConnector:self requestOperationCompleted:_request];
  }
  
  // 保持しているrequestの解放
  [operations removeObject:anOperation];
  if ([operations count] <= 0) {
   [self.delegateOperationDictionary removeObjectForKey:pointerOfDelegate];
  }
  GNRLoggerDebug(@"-- operation  completed --");
 }];
 

operationのアドレス情報を別変数に入れることで解決しました。
// オペレーションがqueueから削除された時の処理設定
 NSNumber *p = [NSNumber numberWithInteger:(NSInteger)anOperation];
 [anOperation setCompletionBlock:^{
  // delegateに通知
  if (_delegate) {
   [_delegate netWorkConnector:self requestOperationCompleted:_request];
  }
  
  // 保持しているrequestの解放
  [operations removeObject:(id)[p integerValue]];
  if ([operations count] <= 0) {
   [self.delegateOperationDictionary removeObjectForKey:pointerOfDelegate];
  }
  GNRLoggerDebug(@"-- operation  completed --");
 }];
 

まぁ原因の根本はBlocksの知識がしょっぱいからに違いない。。。
このエントリーをはてなブックマークに追加

2012年2月20日月曜日

No previous prototype for function 'functionname'ってwarningの対処

スタティックなメソッドなのにstaticが付いてませんでした。
なので
static int hoge;
こんな感じにstaticをつけてやることで解消しました。
このエントリーをはてなブックマークに追加

2012年2月19日日曜日

viewのx座標だけ、y座標だけ、widthだけ、heightだけ変更したい

UIViewのwidthだけ変更したいのに
@interface UIView (extend)
aView.frame = CGRectMake(aView.frame.origin.x, aView.frame.origin.y, 100, aView.frame.size.height);
@end
って書くのまんどくせー。
ってことで下記のようなUIViewの拡張メソッドを用意して使っています。

@interface UIView (extend)
- (void)setX:(NSInteger)x;
- (void)setY:(NSInteger)y;
- (void)setWidth:(NSInteger)width;
- (void)setHeight:(NSInteger)height;
- (void)setOrigin:(CGPoint)point;
- (void)setSize:(CGSize)size;
@end
 


#import "UIView+extend.h"


@implementation UIView (extend)



- (void)setX:(NSInteger)x

{

 self.frame = CGRectMake( x, self.frame.origin.y, self.frame.size.width, self.frame.size.height );

}

- (void)setY(NSInteger)y

{

 self.frame = CGRectMake( self.frame.origin.x, y, self.frame.size.width, self.frame.size.height );

}

- (void)setWidth:(NSInteger)width

{

 self.frame = CGRectMake( self.frame.origin.x, self.frame.origin.y, self, view.frame.size.height );

}

- (void)setHeight:(NSInteger)height

{

 self.frame = CGRectMake( view.frame.origin.x, view.frame.origin.y, view.frame.size.width, height );

}



- (void)setOrigin:(CGPoint)point {

 self.frame = CGRectMake(point.x, point.y, self.frame.size.width, self.frame.size.height);

}

- (void)setSize:(CGSize)size {

 self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, size.width, size.height);

}



- (void)setViewSizeHalf:(UIView*)view {

 view.frame = CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width/2, view.frame.size.height/2);

}

@end
 

#import "Hoge.h"
#import "UIView+extend.h"

@implementation Hoge
- (id)init
{
 if (self = [super init]) {
  UIView *aView = [[[UIView alloc] init] autorelease];
  [aView setX:100];
 }
 return self;
}

@end
 
実績の無いソースコードなのでコピペじゃコンパイル通らないかもしれません。
このエントリーをはてなブックマークに追加

2012年2月17日金曜日

tabBarControllerに配置したnavigatioController内でviewControllerをpushした際にタブバーを非表示

タブターコントローラー(UITabBarController)に配置したナビゲーションコントローラー(UINavigatioController)内でviewControllerをpushした際にタブバー(tabbar)を非表示にするにはviewControllerのinitに下記コードを記述します。
-(id)init
{
 if( self=[super init] ){
  self.hidesBottomBarWhenPushed = YES;
 
 }
 return self;
}
 
ナビゲーションバー見たいにいつでも表示/非表示できないん?
このエントリーをはてなブックマークに追加

xcode4 + lionで自作テンプレートを配置する場所

ファインダーのタスクバーメニューから[移動]->[フォルダへ移動]を選択して
下記のパスを入力して[移動]をクリック
/Users/hoge/Library/Developer/Xcode

hogeの部分はアイコンがついてるフォルダ名です。
このエントリーをはてなブックマークに追加

2012年2月16日木曜日

iOS5でwent isFinished=YES without being started by the queue it is inの対処

iOS5以前はNSOperationをキャンセルする為にcancelメソッド内でisFinishedYESを設定すればよかったのですが、iOS5になってから「went isFinished=YES without being started by the queue it is in」っていうlogがコンソールに表示されるようになってしまいました。
どうやら
「実行されてないのに終了しちゃだめね♥」
といっているようです。これを回避する為に実装を下記のように修正しました。
 
[self setValue:[NSNumber numberWithBool:YES] forKey:@"isFinished"];
 
 
[self setValue:[NSNumber numberWithBool:YES] forKey:@"isExecuting"];
[self setValue:[NSNumber numberWithBool:NO] forKey:@"isExecuting"];
[self setValue:[NSNumber numberWithBool:YES] forKey:@"isFinished"];
 
これがあるべき姿かどうかはわかりませんが、キャンセルしてもlogに「went isFinished=YES without being started by the queue it is in」は表示されなくなれました。
めでたし、めでたし。。。なのか?
このエントリーをはてなブックマークに追加

2012年2月10日金曜日

Apple Push Notification Serviceで気をつける事あれこれ

Appl Push Notification Service(APNS)の実装で結構はまったのでメモっとく

①全般

  1. リモート通知はシュミレータではサポートされていないので実機転送する必要がある。
  2. プロヴィジョニングプロファイルに含めるApp IDのBundle Identifierにワイルドカード(*)は使用出来ない。
  3. 作成したApp IDのConfigureでDevelopment Push SSL CertificateをEnabledにする必要がある。
  4. App IDを作成後、作成されたAppIDを選択しEditボタンを押したら、Push Notifications の Development SSL Certificate の Create certificateボタンをおしてcertificateする必要があります。
  5.  認証局に証明書を要求する際に「鍵ペア情報を指定」にチェックを入れておく。
  6. 「アプリケーションの有効な"aps-environment"エンタイトルメント文字列が見つかりません」ってエラーが発生したら使用しているプロビジョニングプロファイルでApple Push Notification serviceが扱えないってこと。
  7. Info.plistのBundle identifierはApp IDで指定した文字列に書き換える必要がある。
  8. Releaseモードでビルドする。
  9. APNSへの接続先urlは開発用(ssl://gateway.sandbox.push.apple.com:2195)とリリース用(ssl://gateway.push.apple.com:2195)がある。
  10. OKボタンのみ表示したい場合の例)'alert' => array('body' => 'aaa', 'action-loc-key' => '')
  11. デバイストークンは変更される可能性があるのでキャッシュしてプロバイダに渡してはいけません。常に、デバイストークンは必要になったときにその都度システムから取得します。by「LocalNotificationおよびPush Notificationプログラミングガイド」キャッシュはOSが勝手にやってます。
  12. 検証が不十分ではあるが設定にて「通知のスタイル:なし」「Appアイコンバッジ表示:OFF」「サウンド:OFF」の状態で
    registerForRemoteNotificationTypesの応答を受信することができずアプリがフリーズする現象が確認されている。iOS7 + iPad mini retina

②パスワード不要のPEMファイルの作り方

予めaps.p12を作成しておく
$ openssl pkcs12 -clcerts -nokeys -in aps.p12 -out aps_cert.pem
$ openssl pkcs12 -nocerts -in aps.p12 -out aps_key.pem
$ openssl rsa -in aps_key.pem -out aps_key_noenc.pem
$ cat aps_cert.pem aps_key_noenc.pem > aps_dev.pem

Xcode 5 完全攻略にもっと簡単な方法が記述されています。



③ios8.0からデバイストークンの取得方法がかわりました。



④デバイストークンは16進数の文字列を使う。以下デバイストークンをNSDataから16進数文字列に変換するコード例






⑤クライアントがpush通知を受け取る状態は大きく分けて3パターン

    ◎クライアントがフォアグラウンドで実行されている場合。
  1. application:didReceiveRemoteNotification:が呼び出される。
  2. application.applicationStateの値はUIApplicationStateActive
    ◎クライアントがバックグラウンドで起動されている場合にpush通知からクライアントを起動した場合。

  1. application:didReceiveRemoteNotification:が呼び出される。
  2. application.applicationStateの値はUIApplicationStateInactive
    ◎クライアントが起動されていない場合にpush通知からクライアントを起動した場合。
  1. application:didFinishLaunchingWithOptions:が呼び出される。
  2. NSDictionary *userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];でデータを受け取ることができる。

⑥アプリ内に情報が通知される、されない


1.アプリフォアグラウンド
通知される


2.アプリバックグラウンド
閉じる:通知されない
表示:通知される
OK:通知されない


3.アプリ未起動
閉じる:通知されない
表示:通知される
OK:通知されない


4.アプリフォアグラウンド+スリープ
OKボタンでない配置:通知される
OK:通知されない


5.アプリバックグラウンド+スリープ
OKボタンでない配置:アプリがフォアグラウンドへ遷移し通知される
OK:通知されない


6.アプリ未起動+スリープ
OKボタンでない配置:アプリが起動され通知される
OK:通知されない





    このエントリーをはてなブックマークに追加