まゆたまガジェット開発逆引き辞典

電子工作やプログラミングのHowtoを逆引き形式で掲載しています。作りたいモノを決めて学んでいくスタイル。プログラマではないので、コードの汚さはお許しを。参照していないものに関しては、コピペ改変まったく問いません

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);//あなたは今日傘を使わないでしょう