UILabelを大量に作る
UIImageを大量に作るにはここを改良してファイル名生成のところをfor文で回してあげれば良いのですが、UILabelはちょっとめんどうです。
UILabelを配列の数だけ生成し、位置と角度をランダムにしてみました。
※Labelを破棄する場合の処理を追加しました。
以下の場合、通常だと[_label removeFromSuperview]; で破棄(消す)ことができますが、生成した直後のものしか消してくれません(以下だと2つ残ってしまう)。
すべて消す場合は、背景が透明のViewを新たに作ってひも付けし、LabelのみそのViewの上にaddSubviewして、そのViewごと破棄すればOKです。
コードは以下。IBやStoryboardを使わずコードのみで生成するという点に注意です。
・ViewController.h Labelをまるごと破棄(消す)場合はこの処理が必要
@property (weak, nonatomic) IBOutlet UIView *labelview; - (IBAction)clearText:(id)sender;
・ViewController.m
- (void)viewDidLoad { [super viewDidLoad]; //表示する文字を配列にまとめる NSArray *myArray = [NSArray arrayWithObjects:@"まどか", @"ほむら", @"さやか", nil]; for(NSString *text in myArray){ //10-170までランダムの数値を出す int labelx = 10 + arc4random() % 160; //50-250までランダムの数値を出す int labely = 50 + arc4random() % 200; //回転角、0-360までランダムの数値を出す int labeltrans = 0 + arc4random() % 360; //ラベル生成 UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(labelx, labely, 100,20)]; //背景色設定 label.backgroundColor = [UIColor yellowColor]; //回転角設定 label.transform = CGAffineTransformMakeRotation(labeltrans); [label setText:text]; [self.view addSubview:label]; //ラベルを消す必要がある場合は、上を以下のように書き換える [_labelview addSubview:label]; } } //ラベルを消す処理 - (IBAction)clearText:(id)sender { [_labelview removeFromSuperview]; }
Objective-CでYahooテキスト解析APIのキーワード抽出を使う
結果がXMLで出て来るので、それをどう文字列なり配列にするかがキモですね。
didEndElementで出力結果をどう表示させるか設定する場面でミスると、出力結果を最終的に処理する部分で苦労することになるので、そこだけ注意です。
流れとしては、
1.ここの「作ろう」からアプリケーションを登録
2.アプリケーションIDが表示されたら、使いたいAPIのリクエストURLをブラウザに入力してテストしてみる。結果が出たらOK。ただしYahoo検索系のAPIはアップグレード版でないと動かない確率が高い模様です。
例:テキスト解析のキーワード抽出APIを使って「エヴァの劇場版もうすぐ!」を解析する場合は以下を入力
http://jlp.yahooapis.jp/KeyphraseService/V1/extract?appid=1234567&sentence=エヴァの劇場版もうすぐ!
なお、「1234567」には登録したアプリケーションのIDを入力してください。またパラメータはここを参考にしてください。
3.以下のコードを入力
以下のコードの@"Result"と@"Keyphrase"は2.を行うと出てくる「Result」フィールドと「Keyphrase」フィールドです。
・ViewController.h
#import <UIKit/UIKit.h> @interface ViewController : UIViewController <NSXMLParserDelegate> { NSMutableArray *results; BOOL inKeyword; NSMutableString *strKeyword; NSMutableArray *resultArray; } //ボタンを押すと解析開始 - (IBAction)KaisekiStart:(id)sender; @end
・ViewController.m
... - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. } //XMLの設定 - (void)loadXML { NSString *kaisekiName = @"エヴァの劇場版もうすぐ!"; //UTF8でエンコードする NSString *encodStr = [kaisekiName stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; NSString *xmlStr = [NSString stringWithFormat: @"http://jlp.yahooapis.jp/KeyphraseService/V1/extract?appid=1234567&sentence=%@", encodStr]; NSURL *url = [NSURL URLWithString:xmlStr]; //NSXMLParserのインスタンスを生成して初期化 NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url]; [parser setDelegate:self]; [parser parse]; } // XMLの解析が開始したときに呼ばれる。初期化や解析の準備をする - (void)parserDidStartDocument:(NSXMLParser *)parser { // 初期化処理 results = [NSMutableArray array]; inKeyword = NO; } // 解析終了、UILabel等に表示させたい場合はここに書く - (void)parserDidEndDocument:(NSXMLParser *)parser { //結果を出力する resultArray = [NSMutableArray array]; for (NSString *result in results) { //NSLog(@"%@", result); [resultArray addObject:result]; } NSString *resultArraystr = [resultArray componentsJoinedByString:@","]; NSLog(@"%@",resultArraystr); } // 開始タグが見つかったら行う処理、タグが2つ以上の場合はifの後にelse ifをつける //タグが見つかったらテキストが読み込まれるので、そのテキストを入れておく準備をする - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict { if ([elementName isEqualToString:@"Keyphrase"]) { inKeyword = YES; strKeyword = [NSMutableString string]; } } // 終了タグが見つかったら行う処理 //タグが2つ以上の場合はelse ifの後にelse ifをつける - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { if ([elementName isEqualToString:@"Result"]) { NSString *resultStr = [NSString stringWithFormat:@"%@",strKeyword]; [results addObject:resultStr]; } else if ([elementName isEqualToString:@"Keyphrase"]) { inKeyword = NO; } } // テキストデータ読み込み - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { if (inKeyword) { [strKeyword appendString:string]; } } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } - (IBAction)KaisekiStart:(id)sender { [self loadXML]; } @end
元の文を入れ替えて違う文にする
またテキストネタです。Objective-Cでマルコフ連鎖をやろうと思ったんですが、どうも上手くいかなったので似た感じで「元の文を入れ替えて違う文にする」のをやってみました。
流れとしてはこんな感じ。たぶんコードがめちゃくちゃだと思うので、だめだこりゃと思ったら直してください。
1.元の文を。で分割する
例:元の文 ぼくはリンゴとみかんを食べた。キミはチキンとサラダを食べた。
文1:ぼくはリンゴとみかんを食べた
文2:キミはチキンとサラダを食べた
2.文1.2それぞれに形態素解析を行って分かち書きをする(以下を参照)
http://d.hatena.ne.jp/prince9/20120917/1347873368
文1を分かち書きすると、ぼく/は/リンゴ/と/みかん/を/食べ/た
3.接尾語とその前の単語をくっつけて文字列にする
例:文1 ぼくは/リンゴと/みかんを/食べた
4.3.を配列にして、ボタンを押すとexchangeObjectAtIndexを使ってランダムに入れ替える
以下サンプルです。もっと効率の良いやり方があると思います。とにかくぐちゃぐちゃですが、とりあえず公開してみました。
分かち書きに関しては前の記事同様、こちらの記事を参考にさせて頂きました。
・ViewController.h
#import <UIKit/UIKit.h> @interface ViewController : UIViewController { //元の文 NSString *hoge; //なんちゃってマルコフ連鎖処理用の配列1 NSMutableArray *Matome; //1文目形態素解析結果の配列1 NSMutableArray *persistentArray; //1文目形態素解析結果の配列2 NSMutableArray *persistentArray2; //。で分割 NSString *str1; NSString *str2; //1つ目の文分割後統合文字列 NSString *strM1;NSString *strM2;NSString *strM3;NSString *strNokori; } - (IBAction)changeRand:(id)sender; //なんちゃってマルコフ連鎖1文目 - (void)NanMarkov1; //なんちゃってマルコフ連鎖2文目 - (void)NanMarkov2; //形態素解析1文目 - (void)token1; //形態素解析2文目 - (void)token2; @end
・ViewController.m
#import "ViewController.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. hoge = @"ぼくはリンゴとみかんを食べた。キミはチキンとサラダが好きだ。"; NSArray *names = [hoge componentsSeparatedByString:@"。"]; str1 = [names objectAtIndex:0]; str2 = [names objectAtIndex:1]; NSLog(@"1番目=%@,2番目=%@",str1,str2); [self token1]; [self token2]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } - (void)token1 { //トークン解析に必要なもの CFLocaleRef locale; // ロケール:tokenizer生成に使用 CFRange range; // 解析用範囲:tokenizer生成に使用 : のちに検知されたトークンの範囲用として使用 {//トークン解析に必要なもの:初期化 range = CFRangeMake(0, [str1 length]); locale = CFLocaleCopyCurrent();// !!!: 要CFRelease } //トークン解析してくれる子 CFStringTokenizerRef tokenizer; // トークン解析してくれるよ !!!: 要CFRelease tokenizer = CFStringTokenizerCreate(kCFAllocatorDefault, (CFStringRef)CFBridgingRetain(str1), range, kCFStringTokenizerUnitWordBoundary, locale); CFStringTokenizerTokenType tokenType; // 見つかったトークンの状態 // 最初に見つかったトークンの状態で初期化 tokenType = CFStringTokenizerGoToTokenAtIndex(tokenizer, 0); persistentArray = [NSMutableArray array]; //トークン毎ループ while (tokenType != kCFStringTokenizerTokenNone) { // // range を解析用範囲から見つかったトークンの範囲へと使用方法を変更 // range = CFStringTokenizerGetCurrentTokenRange(tokenizer); //出力結果 NSString *relustStr = [str1 substringWithRange:NSMakeRange(range.location, range.length)]; //NSLog(@"結果=%@",relustStr); //解析結果から配列を作成 [persistentArray addObject:relustStr]; tokenType = CFStringTokenizerAdvanceToNextToken(tokenizer); } [self NanMarkov1]; CFRelease(locale); CFRelease(tokenizer); } - (void)token2 { //トークン解析に必要なもの CFLocaleRef locale2; // ロケール:tokenizer生成に使用 CFRange range2; // 解析用範囲:tokenizer生成に使用 : のちに検知されたトークンの範囲用として使用 {//トークン解析に必要なもの:初期化 range2 = CFRangeMake(0, [str2 length]); locale2 = CFLocaleCopyCurrent();// !!!: 要CFRelease } //トークン解析してくれる子 CFStringTokenizerRef tokenizer2; // トークン解析してくれるよ !!!: 要CFRelease tokenizer2 = CFStringTokenizerCreate(kCFAllocatorDefault, (CFStringRef)CFBridgingRetain(str2), range2, kCFStringTokenizerUnitWordBoundary, locale2); CFStringTokenizerTokenType tokenType2; // 見つかったトークンの状態 // 最初に見つかったトークンの状態で初期化 tokenType2 = CFStringTokenizerGoToTokenAtIndex(tokenizer2, 0); persistentArray2 = [NSMutableArray array]; //トークン毎ループ while (tokenType2 != kCFStringTokenizerTokenNone) { // // range を解析用範囲から見つかったトークンの範囲へと使用方法を変更 // range2 = CFStringTokenizerGetCurrentTokenRange(tokenizer2); //出力結果 NSString *relustStr2 = [str2 substringWithRange:NSMakeRange(range2.location, range2.length)]; //NSLog(@"結果=%@",relustStr); //解析結果から配列を作成 [persistentArray2 addObject:relustStr2]; tokenType2 = CFStringTokenizerAdvanceToNextToken(tokenizer2); } [self NanMarkov2]; CFRelease(locale2); CFRelease(tokenizer2); } - (void)NanMarkov1 { //配列をコピー NSMutableArray *copyarr = [persistentArray mutableCopy]; NSMutableArray *nokori = copyarr; int cnt = [nokori count]; if (cnt <= 6) { NSString *strLast = [nokori componentsJoinedByString:@""]; NSLog(@"そのまま=%@",strLast); } else { [nokori removeObjectsInRange:NSMakeRange(0, 6)]; //分割後 NSString *strNokoriMae = [nokori componentsJoinedByString:@""]; NSString *Bunbatumaru = @"。"; strNokori = [strNokoriMae stringByAppendingString:Bunbatumaru]; NSString *strA1 = [persistentArray objectAtIndex:0]; NSString *strA2 = [persistentArray objectAtIndex:1]; strM1 = [strA1 stringByAppendingString:strA2]; NSLog(@"最初配列0=%@",strM1); NSString *strA3 = [persistentArray objectAtIndex:2]; NSString *strA4 = [persistentArray objectAtIndex:3]; strM2 = [strA3 stringByAppendingString:strA4]; NSLog(@"2番目配列1=%@",strM2); NSString *strA5 = [persistentArray objectAtIndex:4]; NSString *strA6 = [persistentArray objectAtIndex:5]; strM3 = [strA5 stringByAppendingString:strA6]; NSLog(@"3番目配列2=%@",strM3); NSLog(@"残り配列3=%@",strNokori); } } - (void)NanMarkov2 { //配列をコピー NSMutableArray *copyarr2 = [persistentArray2 mutableCopy]; NSMutableArray *nokori2 = copyarr2; int cnt2 = [nokori2 count]; if (cnt2 <= 6) { NSString *strLast2 = [nokori2 componentsJoinedByString:@""]; NSLog(@"2文目そのまま=%@",strLast2); } else { [nokori2 removeObjectsInRange:NSMakeRange(0, 6)]; //分割後 NSString *strNokoriMae2 = [nokori2 componentsJoinedByString:@""]; NSString *Bunbatumaru2 = @"。"; NSString *strNokori2 = [strNokoriMae2 stringByAppendingString:Bunbatumaru2]; NSString *strB1 = [persistentArray2 objectAtIndex:0]; NSString *strB2 = [persistentArray2 objectAtIndex:1]; NSString *strMB1 = [strB1 stringByAppendingString:strB2]; NSLog(@"2文目最初配列0=%@",strMB1); NSString *strB3 = [persistentArray2 objectAtIndex:2]; NSString *strB4 = [persistentArray2 objectAtIndex:3]; NSString *strMB2 = [strB3 stringByAppendingString:strB4]; NSLog(@"2文目2番目配列1=%@",strMB2); NSString *strB5 = [persistentArray2 objectAtIndex:4]; NSString *strB6 = [persistentArray2 objectAtIndex:5]; NSString *strMB3 = [strB5 stringByAppendingString:strB6]; NSLog(@"2文目3番目配列2=%@",strMB3); NSLog(@"2文目残り配列3=%@",strNokori2); //1文目1+2はstrM1、1文目3+4はstrM2、1文目4+5はstrM3、1文目残りはstrNokori Matome = [NSMutableArray array]; [Matome addObject:strM1]; [Matome addObject:strM2]; [Matome addObject:strM3]; [Matome addObject:strNokori]; [Matome addObject:strMB1]; [Matome addObject:strMB2]; [Matome addObject:strMB3]; [Matome addObject:strNokori2]; } } - (IBAction)changeRand:(id)sender { int cnt2 = [Matome count]; if (cnt2 <= 3) { NSLog(@"そのまま=%@",hoge); } else { int archr = 1 + arc4random() % 3; int archr2 = 5 + arc4random() % 3; [Matome exchangeObjectAtIndex:archr withObjectAtIndex:archr2]; NSString *strRand = [Matome componentsJoinedByString:@""]; NSLog(@"最終出力=%@",strRand); } } @end
連番ファイルを読み込んで表示
パラパラアニメなどで連番ファイルを読み込んだり、ファイル名に変数を使いたい場合のファイル指定の方法です。ド基本かもですが、個人的にObjective-Cでは初めてだったので(oFではあったけど)。
まず3つのPNGファイルを用意しておきます。ファイル名は1Butterfly@2x.png・2Butterfly@2x.png・3Butterfly@2x.pngの3つ。Butterfly1@2x.pngだと後でちょっと困るので、番号は先頭につけています。
ボタンを押すと数がカウントされて、その数がファイル名に含まれているものを表示します。カウント1のときには1Butterfly@2x.pngを表示、カウント2のときは2Butterfly@2x.pngを表示という具合です。
以下サンプルです。これはPNGファイルを読み込ませていますが、前回のplistでも良いですね。
・ViewController.h
#import <UIKit/UIKit.h> @interface ViewController : UIViewController { int count; } @property (weak, nonatomic) IBOutlet UIImageView *PictRenban; - (IBAction)countUp:(id)sender; @end
・ViewController.m
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. count = 0; } ... - (IBAction)countUp:(id)sender { count = count + 1; if (count == 4) { count = 1; } NSLog(@"%d",count); //数値を文字列に NSString *ImageNum = [NSString stringWithFormat : @"%d", count]; NSString *Imagename = [NSString stringWithFormat:@"%@Butterfly@2x.png",ImageNum]; _PictRenban.image = [UIImage imageNamed:Imagename]; } @end
ファイル名の指定をもしButterfly1@2x.pngとすると、"Butterfly%@@2x.png"となってエラーが出てしまいます。おそらくこう指定しても読み込むやり方はあると思うのですが、メンドいので先頭に%@を持ってきて、"%@Butterfly@2x.png"としました。
iOS6でTwitterのタイムラインを取得
iOS6からTwitter.frameworkが使えなくなりました(動くけど警告が出る)。
Social.frameworkとやらを使えということらしいです。
タイムラインの読み込みに関してはこちらが詳しいです。
テキストだけ取り出したい場合は、
・.h
#import <UIKit/UIKit.h> #import <Social/Social.h> #import <Accounts/Accounts.h> @interface ViewController : UIViewController { NSString *Twstr; NSMutableArray *tweetTextArray; } @end
・.m
if(timeline){ for (NSDictionary *tweet in timeline) { [tweetTextArray addObject:[tweet objectForKey:@"text"]]; Twstr = [tweetTextArray componentsJoinedByString:@","]; } }else{ NSLog(@"error: %@",jsonError); } } NSLog(@"%@", Twstr);
とすればOKです。
文字列を大量の条件で置換する
またまた文字列ネタです。
ここで条件を列挙して文字列を置換することをやりましたが、それを一気にやる方法を作りました。
plistを使います。
まず手順。
1.プロジェクト名が書いてあるファイルを右クリックしてNew Fileを選び、iOS→Resource→Property Listをクリック、てきとーに名前をつける(ここではhogeにしました)
2.hoge.plistを編集する。Rootの右側をクリックすると+マークが出て来るので、それを押してKeyを入力する。ValueはKeyを入力した列にあるValueをダブルクリックすると入力できるので、それぞれ入力する。TypeはすべてStringにする。Keyが置換対象の文字で、Valueが置換後の文字です。
3.以下を入力する
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. //置換する文字列 NSString *serchStr = @"カツオはサマナー。波平は...?"; //plistの読み込み。ofType:@"plist"はそのままでpathForResource:をファイル名にする NSString* path = [[NSBundle mainBundle] pathForResource:@"hoge" ofType:@"plist"]; NSDictionary* dictionary = [NSDictionary dictionaryWithContentsOfFile:path]; //キーを全部取り出して配列にする NSArray *ar = [dictionary allKeys]; //値を全部取り出して配列にする NSArray *ar2 = [dictionary allValues]; //変換の処理 for(int i=0; i<[ar count]; i++){ serchStr = [serchStr stringByReplacingOccurrencesOfString: [ar objectAtIndex:i] withString: [ar2 objectAtIndex:i]]; } //最終結果 NSLog(@"%@",serchStr); //ワカメはサマナー。フネは...? } ...
複数の条件で文字を置換する
複数の条件で文字を置換するのにだいぶ手間取ってしまった・・・まさか列挙するだけで良いとは知りませんでした。正規表現使うのかと思ってた。
ただこの場合、数が多いとやっかいですね。まとめて書く方法は何かないものかしら・・・
ルール:左が置換前、右が置換後
私→あなた
明日→今日
かさ→傘
使う→使わない
NSString *str = @"私は明日かさを使うでしょう"; NSString* string3 = [[[[str stringByReplacingOccurrencesOfString:@"私" withString:@"あなた"] stringByReplacingOccurrencesOfString:@"明日" withString:@"今日"] stringByReplacingOccurrencesOfString:@"かさ" withString:@"傘"] stringByReplacingOccurrencesOfString:@"使う" withString:@"使わない"]; NSLog(@"%@",string3);//あなたは今日傘を使わないでしょう