忍者ブログ
[4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。


xcodeを最新の環境の5.1にバージョンアップしてから、初めてadmobを入れようとしては待ってしまった。

admob広告表示に関しては、一度実装してみた後は、コピペですんでいた。
今回も、今までと同じように前回作成したアプリのソースをコピペした所、エラーになった。

エラーの内容は、以下のようなものが出てきた。
===================================================================
ld: warning: ld: warning: ld: warning: ignoring file /ファイルのパス/adkit/libAdapterIAd.a, missing required architecture arm64 in file /ファイルのパス/adkit/libAdapterIAd.a (3 slices)ignoring file /ファイルのパス/libAdapterNend.a, missing required architecture arm64 in file /ファイルのパス/adkit/libAdapterNend.a (3 slices)ignoring file /ファイルのパス/adkit/libGoogleAdMobAds.a, missing required architecture arm64 in file /ファイルのパス/libGoogleAdMobAds.a (3 slices) 
Undefined symbols for architecture arm64:
  "_OBJC_CLASS_$_GADRequest", referenced from:
      objc-class-ref in CategoryEditViewController.o
      objc-class-ref in MainViewController.o
      objc-class-ref in ItemEditViewController.o
  "_kGADAdSizeBanner", referenced from:
      -[CategoryEditViewController viewDidLoad] in CategoryEditViewController.o
      -[MainViewController viewDidLoad] in MainViewController.o
      -[ItemEditViewController viewDidLoad] in ItemEditViewController.o
  "_OBJC_CLASS_$_GADBannerView", referenced from:
      objc-class-ref in CategoryEditViewController.o
      objc-class-ref in MainViewController.o
      objc-class-ref in ItemEditViewController.o
  "_kGADAdSizeLeaderboard", referenced from:
      -[CategoryEditViewController viewDidLoad] in CategoryEditViewController.o
      -[MainViewController viewDidLoad] in MainViewController.o
      -[ItemEditViewController viewDidLoad] in ItemEditViewController.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
===================================================================
このブログでも以前に書いていた部分に引っかかったのかと思い見直してみたが、ちょっと違う。

以前は、単純にビルドの設定を変更する事で対応できたのだが、今回は、前回と同じ選択肢が存在しない。
それに、他にもちょっと怪しい指摘もあるので、全体的に見直しを行う事にした。

まずは、組み込むadmonやAppBankのファイルのバージョンをチェック。
案の定、既に古いものを使用していた。

一度、使い始めた後に、この部分に関して、あまりバージョンアップをしていなかった。
早速、全て、最新のファイルを取得し組み込むがあまり変わらない。

というよりも、エラーが増えた。
===================================================================
  "_AVAudioSessionPortBuiltInSpeaker", referenced from:
      -[GADDevice audioRouteUsingAVAudioSession] in libGoogleAdMobAds.a(GADDevice.o)
  "_AVAudioSessionPortHeadphones", referenced from:
      -[GADDevice audioRouteUsingAVAudioSession] in libGoogleAdMobAds.a(GADDevice.o)
  "_OBJC_CLASS_$_AVAudioSession", referenced from:
      objc-class-ref in libGoogleAdMobAds.a(GADDevice.o)
  "_OBJC_CLASS_$_CTTelephonyNetworkInfo", referenced from:
      objc-class-ref in libGoogleAdMobAds.a(GADDevice.o)
===================================================================
こんなのが増えている。

これは、中をじっくり見ると、どうも、必要なframeworkが増えているようだった。
結果的に、以前使っていた時よりも、下記の2個が必要なっていた。
・AVFoundation.framework
・CoreTelephony.framework

この追加で、とりあえず、エラーはなくなったが、64bitでビルドするとワーニングが残る。
そのまま実行すると、AppBankの広告は表示されない。
ログに広告の取得失敗が残っている。
これこそ、以前と同じなのだが、ビルドの設定に以前と同じものはなくなっている。

しかたなく、「Build Setting」の「Architectures」を「Other」を選択。
そこで、「armv7」「armv7s」の2項目を入力し、他の項目は削除しておく。
この設定で、ワーニングは消えた。
動作も、問題なく広告表示されるようになったので、これでよいと思われる。

以前のバージョンでは、選択肢にあったので簡単であったのに、今回は、手入力が必要になったようだ。

拍手[3回]

PR

前回に続き、Bluetoothの通信についての内容。

前回記載した対応で、通信の確立を行い、簡単なデータの送受信(短い文字列)の確認まで出来ていた。
ここから、今回開発するデータの形式にあわせてカスタマイズしていくのだが、また引っかかってしまった。

ある程度、送受信するデータの整形を実装し、何度かテストを行っていると、直に接続が切れてしまう事があった。
特に、切断理由が出る訳でもないため、意味が分からなかった。

何度かパターンをかえながらテストを行っている時に今回の実装の為に調べた中で思い出した事があった。

GameKitのGKSessionやGKPeerPickerControllerを使った場合、データサイズが1000バイトまでが推奨サイズらしい。
さらに、87Kbの制限があるとの記載まである。
しかし、このサイズを超えても、動作したと報告もあったので、その時にはあまり気にしなかった。
しかし、今回確認した内容を考えた場合、データサイズの制限に引っかかっている可能性が高い。

仕方なく、データを分割して通信を行う事にした。
何とも面倒な事だが仕方がない。
まず始めに、推奨サイズに指定されている1000バイトで実装を進める。
(当然、サイズはデファイン化し、最終的には、バランスのよいサイズを探る予定)

まずは、送信側でNSData型にまとめたデータを分割する。

    NSRange dataRange;
    NSInteger dataSize = pinData.length;
    NSInteger dataSplitCount = dataSize/DATA_SPLIT_SIZE;

    dataRange.length = DATA_SPLIT_SIZE;
    dataRange.location = 0;
    NSMutableArray *dataArray = [NSMutableArray array];
    for(NSInteger cnt = 0;cnt<dataSplitCount;cnt++)
    {
        [dataArray addObject:[sendData subdataWithRange:dataRange]];
        dataRange.location += DATA_SPLIT_SIZE;
    }
    // 最後のデータは、レングスを調整してから処理を行う
    dataRange.length = dataSize%DATA_SPLIT_SIZE;
    [dataArray addObject:[pinData subdataWithRange:dataRange]];

このようにして、データの分割を行う。
そして、受信側は、これの反対の処理を行う

    NSMutableData *receiveData;

これで、保存エリアを確保した状態で、下記のように受信データをつなげていく。
    // 受信データを保存する
    [receiveData appendData:data];

これでを繰り返す事で、大きなデータに戻す事が出来る。
この、「NSMutableData 」は、NSDataとしてそのまま使用する事が可能。
その為、最後のデータを受信してから下記処理を行う事で元のデータ構造に戻す事が出来る。

    DataObject *receiveObject = [NSKeyedUnarchiver unarchiveObjectWithData: receiveData];

この実装で動作確認をすると、問題なくデータの送受信が出来た。
何とも面倒な処理を書く必要があった。

しかし、逆に大きなデータの転送を行う場合には、分割したいくつ目まで送受信を行ったのかを監視するとこで、進捗状況を表示する事が出来る。
この辺りをうまく整理して実装する事で、見た目のよいものを作る事が出来ると思う。

あとは、最初の方に書いているように、1回のデータ送受信のサイズを、安定性、スピード等を考えて、いろいろ試しながら調整する必要があると思われる。

拍手[0回]


今開発しているアプリで、Bluetoothを使用して、通信を行うものを入れようとしている。
この実装には、かなり苦労してしまったので、残す事にする。

Bluetoothは使った事が無かったので、いつも通りにネットで検索して、実装方法を参考にしていた。

まず始めに、「GameKit.framework」の「GKPeerPickerController」を使う事で実装した。

とりあえず動かしてみると、中途半端に動くので、調べてみると、「GKPeerPickerController」は、iOS7は未サポートであり、現在は、非推奨となっている。
これに変わるものとして、「MultipeerConnectivity.framework」が必要な、「MCBrowserViewController」「MCSession」を使用する方法になっていた。

これに関しても、ネットで検索すると、サンプルソースとともに、解説がいくつもあったので、分かりやすいと思うページを参考にするとよいと思う。

早速、これに置き換えようとして、解説を読んでいくと、新しい「MCBrowserViewController」は、iOS7からしか使用できないと書かれている。
仕方ないと思い、OSのバージョンを見て切り分けるように実装し、動作確認してみた。

すると、通信相手を検索にいくのだが、全く発見できない。
「GKPeerPickerController」をiOS7で使った時には、検索する事は出来ていたのに・・・

いろいろ試しながら、調べていくと、どうやら、「GKPeerPickerController」と「MCBrowserViewController」では、通信できないらしい。
これでは、はっきり言って使い物にならないのではないかと思ってしまう。
今回(いつも同じだが)、iOS6とiOS7の実機で確認するようにはしている。
特に今回は、2台で通信するので、それぞれ、別のOSの実機で確認していたから、すぐに気がついた。
一通り作り込んだ後に確認していたら、とんでもない後戻りになったと思う。
その点は、運がよかったのかも・・・

しかし、この事に関しては、あまり情報がなく、ほとんどが、それぞれの方法についての解説のみだった。
iOS6、iOS7の両方をサポートしたアプリを作ることは無理なのかとも思い始めていたが、やっと方法が見つかった。

iOS7の場合、「GKPeerPickerController」は、中途半端に動作するという事がポイント。
具体的には、接続状態が変更された時に呼ばれる「- (void)session:(id)session peer:(id)peerID didChangeState:(GKPeerConnectionState)state」が、切断された時にしか動かない。
この為、接続が確立した事が分からなくなってしまっているのだ。

そこで、対策として、接続処理が終わった時にコールされる「- (void)peerPickerController:(GKPeerPickerController *)picker didConnectPeer:(NSString *)peerID toSession:(GKSession *)session」で、iOS7の場合には、強制的に、「- (void)session:(id)session peer:(id)peerID didChangeState:(GKPeerConnectionState)state」をコールしてしまうと動かす事が出来た。

実際のソースは、下記のイメージ

- (void)peerPickerController:(GKPeerPickerController *)picker didConnectPeer:(NSString *)peerID toSession:(GKSession *)session
{
    // セッションを保管
    currentSession = session;
    // デリゲートのセット
    session.delegate = self;
    // データ受信時のハンドラを設定
    [session setDataReceiveHandler:self withContext:nil];
    
    // ピアピッカーを閉じる
    picker.delegate = nil;
    [picker dismiss];
    
    if (osVersion >= 7.0) {
        // iOS7.0
        if (self.isConnecting == NO)
            [self session:currentSession peer:peerID didChangeState:GKPeerStateConnected];
    }
}

- (void)session:(id)session peer:(id)peerID didChangeState:(GKPeerConnectionState)state
{
    switch (state) {
        case GKPeerStateAvailable:
            // (省略)
            break;
        case GKPeerStateConnecting:
            // (省略)
            break;
        case GKPeerStateConnected:
            // 接続完了
            self.isConnecting = YES;
            // 接続完了後の処理をここに書く(省略)
            break;
        case GKPeerStateDisconnected:
            // (省略)
            break;
        case GKPeerStateUnavailable:
            // (省略)
            break;
        default:
            break;
    }
}

ポイントとなる「GKPeerStateConnected」の部分以外は基本的に省略しているが、上記のような実装で、うまく接続を確立して通信する事が出来た。

ただ、非推奨となっていて、iOS7では、未サポートとされるものを使用して、無理矢理動かした感が強いと思う。
そのため、どんな不具合が出るのか、今は予想できていない。
さらに、Appleの審査で問題とならないのかもよくわからない。

最悪の場合、iOS7専用にしてしまうと思うが、今の所は、このまま開発を進める。
(知り合いにも、iOS7が気に入らないからとアップデートしない人は、数人いるので、まだ、iOS6もサポートしたいと思う。)

最終的に、テスト、アプリ申請と進める上で、問題が出たら(問題なく完了しても)、ここに残す予定。

拍手[3回]


UTableViewを使っているとちょくちょく登場してくるNSIndexPath。

今までは、この詳細まで意識する必要がなかったのであまり気にしていなくて、どこをさしているかが入っているものくらいにしか考えていなかった。
確かに、それで間違っている訳ではないのだが、その詳細についてはよくわからなかった。

今回、テーブル内容の削除や変更と連動していろいろと操作が必要となったので、調べる必要がでたので、ここに残す。

単純に参照する時には、下記のように指定する事で取り出せていた。

    NSInteger row = indexPath.row;

これがあるのだから、中身の設定(変更)も、単純に設定できると思っていたが、そうではなかった。

結果的には下記のようにする事で設定が出来た。

    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:1 inSection:1];

参照と設定の方法が、別々のやり方が必要なのは少し分かりにくいと思う。

拍手[0回]


昨日に続いて、coredataの使い方で躓いてしまったので、また残す事にする。

coredataのデータ更新自体は、サンプルのソースがたくさん出ていて、特に悩む事はないと思う。
しかし、今回は、うまく更新が出来ない現象に当たってしまった。
しかも、シミュレータでは、特に問題なく動作したのだが、実機を使うと失敗してしまった。
この手の現象が最も困ってしまう。

今回は、データベースのデータ構造として、少し複雑な構造を設計していた。
昨日の記事にも書いている事から分かるように、独自のクラスを追加して、データに使用した。
それだけであれば、おそらく問題は出なかったと思う。

データの構造を簡単に書くと、メインの配列があり、そのメンバに、さらに配列を作り、メンバが独自クラスという構造。
簡単に書くとい可能なイメージ。

メインのcoredataから管理するデータ(xcdatamodeldに書いてあるメンバ)

@interface DataGroup : NSManagedObject

NSString *sampleName;
NSMutableArray *arrayObject;
(このNSMutableArrayは、実際には、Transformable)

NSMutableArray *sampleObject;に設定する内容として、下記のクラスを作成

@interface DataObject : NSObject

NSString *itemName;
UIImage *itemObject;
double itemDouble;

こんな感じ。

データの更新タイミングで、単純に変更したパラメータのみ設定して書き込みを行う。
その上で、再読み込みをすると、設定した内容を取り出す事が出来た。
これで問題ないと思って、次の作業を行っていたのだが、しばらくして実機で確認した。

すると、更新して保存、再読み込みと特に問題なく出来たのだが、アプリを再起動して読み込むと、データが消えている。
「arrayObject」に新規の「DataObject」のメンバを追加して保存するのだが、アプリ再起動後は、メンバがいなくなる。
シミュレータで同じ事を行うと、アプリ再起動後も正しく再設定した内容が取り出せる。
この中途半端さ加減に参ってしまった。

いろいろ考えた結果、失敗するパターンの事のみ考えて、下記のような対策を行った。
「arrayObject」に入っているクラスそのものは、使い回していたのをやめて、新規に作成する事にした。

下記が、対応後のソース
    DataGroup *selectedObject = [[self fetchedResultsController] objectAtIndexPath:editGroupNo];
    NSMutableArray *editArray = selectedObject.arrayObject;
    DataObject *editData = [[DataObject alloc]init];

     [editArray addObject:editData];
    
    NSMutableArray *saveArray = [NSMutableArray array];
    NSInteger cnt,loopMax;

    loopMax = editArray.count;
    
    for (cnt=0; cnt<loopMax; cnt++) {
        [saveArray addObject:[editArray objectAtIndex:cnt]];
    }
    
    selectedObject.pinArrayObject = saveArray;
    
    // saveメソッドで更新状態を確定
    error = nil;
    if (![context save:&error]) {
        NSLog(@"error = %@", error);
        abort();
    }


これで、メンバの追加がうまくいくようになった。

しかし、独自クラス内のメンバの内容を更新しても変更されない現象が続けて発生した。
たとえば、上記の構想の「itemName」のみを変更してアプリを起動したままし読み込みをすると、変更されていた。
しかし、アプリを再起動すると、変更前のデータが出てきた。
これも、シミュレータで同じ事を行うと、アプリ再起動後も正しく再設定した内容が取り出せる。

このような現象が起きてしまったら、あまり行いたくない事であったが、一度、削除してから再設定を行う事で、対策する事が出来た。
    DataGroup *selectedObject = [[self fetchedResultsController] objectAtIndexPath:editGroupNo];
    NSMutableArray *editArray = selectedObject.arrayObject;
    DataObject *editData = [editArray objectAtIndex:editItemNo];

    selectedObject.pinArrayObject = nil;
    
    // saveメソッドで更新状態を確定
    error = nil;
    if (![context save:&error]) {
        NSLog(@"error = %@", error);
        abort();
    }

    editData.itemName = @"変更後の文字列";

    NSMutableArray *saveArray = [NSMutableArray array];
    NSInteger cnt,loopMax;

    loopMax = editArray.count;
    
    for (cnt=0; cnt<loopMax; cnt++) {
        [saveArray addObject:[editArray objectAtIndex:cnt]];
    }
    
    selectedObject.pinArrayObject = saveArray;
    
    // saveメソッドで更新状態を確定
    error = nil;
    if (![context save:&error]) {
        NSLog(@"error = %@", error);
        abort();
    }


これで、メンバ内のデータ更新がうまくいくようになった。
coredataは使いやすいような使いにくいような、なかなか謎が多いのかもしれない。

拍手[0回]


前のページ      次のページ

リリース済みアプリ

Silmuvide


PseudoRPT


うつすと!


ChronologyMaker


LASI


3行日記


単位計算機


Marking Map Plus


交通費管理


交通費計算リスト


Markin Map


SheepSleepSheep


RootCalculator


元号変換


PieChart


MeasureShooting


SimpleMapCreator



Applivのレビュー記事
http://app-liv.jp/713163900/

ゆびてんじ


PR



Copyright ©   marble seijin の開発日記   All Rights Reserved
Design by MMIT simple_plain Powered by NINJA TOOLS
忍者ブログ [PR]