6

私のアプリには、sqlite データベースからのデータが必要です。このデータベースのバージョンが付属していますが、定期的に更新する必要があります (ほとんどの場合、月に 1 回)。通常、私はアプリの他の部分の更新を、セットアップした一連の Web サービスを介して XML として送信してきましたが、現在取り組んでいるこの特定のデータベースは非常に大きく (約 20 ~ 30 MB)、そのように送信しようとすると、タイムアウトエラーが発生します。

NSDataデータベースを会社のサーバーに配置してから、オブジェクトにダウンロードしてみました。次に、そのデータ オブジェクトをアプリの Documents ディレクトリに保存しました。アプリを再起動すると、「パスのファイルは SQLite データベースではないようです」というエラーが表示されます。このコードは以下のとおりです。

// Download data
NSURL *url = [NSURL URLWithString:@"http://www.mysite.net/download/myDatabase.sqlite"];
NSData *fileData = [[NSData alloc] initWithContentsOfURL:url];
NSLog(@"%@",fileData); // Writes a bunch of 8 character (hex?) strings

// Delete old database
NSError *error;
NSURL *destination = [app applicationDocumentsDirectory];
destination = [destination URLByAppendingPathComponent:@"myDatabase"];
destination = [destination URLByAppendingPathExtension:@"sqlite"];
NSLog(@"destination = %@",destination);
[[NSFileManager defaultManager] removeItemAtPath:[destination path] error:&error];

// Save into correct location
[fileData writeToURL:destination atomically:YES];
//[NSFileManager defaultManager] createFileAtPath:[destination path] contents:fileData attributes:nil]; // I also tried this, it doesn't work either.

アプリが使用する大規模なデータベースを更新するための標準的な手順はありますか? 私がやろうとしていることは間違っていて、これを行うにはまったく別の方法があるように感じますが、何がわからないのですか。


更新:問題を見つけるためにいくつかのことを試みましたが、何も私に近づきません. サーバーからダウンロードしようとしているデータベースを USB ドライブに置き、次に開発中の Mac に置き、シミュレーターのアプリの Documents フォルダーに置きます。この方法でデータベースを転送してアプリを実行すると、問題なく実行され、すべてのデータを表示できます。

逆に、アプリをシミュレーターから完全に削除して再実行したため、データベースが最初から作成されました。この新しく作成したデータベースを Mac から USB ドライブを使用してサーバーに転送しました。ファイルがサーバーに配置されたら、上記のコード ブロックで「更新のダウンロード」を実行しようとしましたが、次にアプリを起動したときに「パスのファイルは SQLite データベースではないようです」というエラーでクラッシュします。メッセージ。

これらのテストから、ダウンロードしようとしているデータベースに問題があるわけではないと確信しています。「アップデートのダウンロード」コードの何かがデータベースを破損していますが、その理由を突き止めることができず、アプリの起動後にユーザーにアップデートを配信するための受け入れ可能な代替方法も見つかりませんでした。


更新 2: さらに検索を行ったところ、サーバー上のファイルにアクセスするには、ユーザーがユーザー名とパスワードを入力する必要があることがわかりました。NSData上記のコードから戻ってきたのは、実際には認証の課題、またはそれに関連するものであると信じています。そのため、それを で保存するとNSFileManager、sqlite DB として認識されません。

認証を通過するために私が見つけた最も簡単な解決策はhereです。私がやろうとすると(もちろん、リンクで提案されているようNSData *fileData = [NSData dataWithContentsOfURL:url options:NSDataReadingMapped error:&error];に変更した後)、エラーが発生しますが、これは不明なエラーです。私はこれをした後です。この投稿はかなり古いので、まだサポートされているかどうかはわかりません。urlNSCocoaErrorDomain Code=256fileDatanil

の代わりに を使用して、ここで認証の問題に対する別の解決策も見つけました。これはもっと最近のことですが、この例では、これまであまり見たことのない、より高度な構文が使用されています。例からほとんどコピーして貼り付けることができ、私のプロジェクトはエラーなしでビルドされますが、私の. 私は試したNSURLConnectiondataWithContentsOfURLfetchURL:withCompletion:failure:UIViewController

NSError *error;
NSData *fileData;
ExampleDelegate *download = [[ExampleDelegate alloc] init];
[download fetchURL:url withCompletion:fileData failure:&error];

しかし、互換性のないポインターを送信するとビルド エラーが発生します。たとえそれらが何から編集されたとしても、私はストレートNSDataNSErrorasExampleDelegateSuccessとオブジェクトをそれぞれ渡すことができないと思います。私はおそらくそれらを変換するために何かをしなければなりませんが、そのing は上で言及した「高度な構文」の 1 つであり、何をすべきか本当にわかりません。ExampleDelegateFailuretypedeffileDataerrortypedef

彼の例には含まれていませんが、ここNSURLConnectionDelegateで呼び出される別のメソッドを見つけました。これを例のコードに追加するだけで、認証の問題を解決できるはずです。呼び方さえわかれば大丈夫だと思います。その電話に出るために私が何をする必要があるかについて誰かアドバイスがありますか?connection:didReceiveAuthenticationChallenge: fetchURLfileDataerror

4

4 に答える 4

3

@silver_beltが示唆しているように、最終的にAFNetworkingを使用して問題を解決しました。ただし、サブクラス化せずにそれを行うことができました(この質問のフォローアップとして投稿した AFHTTPClient私の回答hereを参照してください)。

最後に#include "AFHTTPRequestOperation.h"、ビューコントローラーの.hファイルを作成し、次に使用した.mファイルを作成する必要がありました

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"ftp://myUsername:myPassword@www.mysite.net/myfile.sqlite"]];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
NSURL *path = [[[app applicationDocumentsDirectory] URLByAppendingPathComponent:@"myfile"] URLByAppendingPathExtension:@"sqlite"];
operation.outputStream = [NSOutputStream outputStreamWithURL:path append:NO];

[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
    {
        NSLog(@"Successfully downloaded file to path: %@",path);
    }
                                 failure:^(AFHTTPRequestOperation *operation, NSError *error)
    {
        NSLog(@"Error in AFHTTPRequestOperation in clickedButtonAtIndex on FlightInfoController.m");
        NSLog(@"%@",error.description);
    }];

[operation start];

実際にダウンロードを開始したかったとき。これが、将来これをやろうとしている人にとってより簡単になることを願っています!

于 2013-05-02T13:59:37.557 に答える
3

定期的に更新する大規模なデータベースがあります。「大」がどの程度大きいかはわかりませんが、メガバイトのデータを更新しています。JSON データとして更新します。JSON は XML よりもオーバーヘッドがわずかに少なく、すぐに利用できるライブラリが多数あります (JSONKit など)。一部のユーザーはデータ接続が不十分で、場合によっては問題が発生します。

さまざまな更新方法をテストしています。1 つの方法は、データを複数の JSON ファイルに分割します。各ファイルは個別にダウンロードされ、個別に保存されます。複数のファイルを使用する場合の利点の 1 つは、1 つのファイルが失敗した場合に、その特定のファイルを再送信するだけでよいことです。

また、複数のスレッドを使用して、一度に最大 5 つのリクエスト/ダウンロードを処理します。これにはより多くの管理が必要ですが、ユーザーにより良いエクスペリエンスを提供するのに役立ちます。AFHTTPClient は、このような処理に非常に優れています。使わないのはもったいない。

于 2013-04-23T04:40:12.143 に答える