2

私はiOSプログラミングが初めてです。

以下のコードを使用して、データベースから画像を取得して配列に保存し、それらの画像をサムネイルに表示しています。

以下のコードを使用すると、すべて正常に動作します。しかし、私には2つの問題があります

  1. データベースからの画像の取得に時間がかかりすぎています。
  2. 8枚以上の画像を保存すると、画像が表示されず、アプリケーションが終了します.8枚未満の画像を撮影すると、サムネイルに画像が表示されます。

このコードの間違いは何ですか?

NSString *docsDir;
NSArray *dirPaths;

// Get the documents directory
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

docsDir = [dirPaths objectAtIndex:0];
array=[[NSMutableArray alloc]init];
array1=[[NSMutableArray alloc]init];

// Build the path to the database file
databasePath =  [docsDir stringByAppendingPathComponent: @"Taukydataaa.db"];

NSFileManager *fn=[NSFileManager defaultManager];
NSError *error;
BOOL success=[fn fileExistsAtPath:databasePath];

if(!success)
{    
    NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"Taukydataaa.db"];
    success = [fn copyItemAtPath:defaultDBPath toPath:databasePath error:&error];
}

const char *dbpath = [databasePath UTF8String];

sqlite3_stmt    *statement;

if (sqlite3_open(dbpath, &contactDB) == SQLITE_OK)
{
    NSString *querySQL = [NSString stringWithFormat: @"select * from tauky"];

    const char *query_stmt = [querySQL UTF8String];

    if (sqlite3_prepare_v2(contactDB, query_stmt, -1, &statement, NULL) == SQLITE_OK)
    {
        while(sqlite3_step(statement) == SQLITE_ROW)
        {

            NSString* email_idField = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement,1)];
            NSString* email_idField1 = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement,0)];
            [array addObject:email_idField];
            [array1 addObject:email_idField1];

            blaukypath =[[NSMutableArray alloc]init];

            for (NSString* path in array)
            {
                [blaukypath addObject:[UIImage imageWithContentsOfFile:path]];
            }

            myScrollView = [[UIScrollView alloc]initWithFrame:CGRectMake(0.0, 0.0, 320.0, 840.0)];
            myScrollView.delegate = self;
            myScrollView.contentSize = CGSizeMake(320.0, 840.0);
            myScrollView.backgroundColor = [UIColor whiteColor];

            [self.view addSubview:myScrollView];

            float horizontal = 8.0;
            float vertical = 8.0;

            for(int i=0; i<[blaukypath count]; i++)
            {
                if((i%4) == 0 && i!=0)
                {
                    horizontal = 8.0;
                    vertical = vertical + 70.0 + 8.0;
                }

                buttonImage = [UIButton buttonWithType:UIButtonTypeCustom];

                [buttonImage setFrame:CGRectMake(horizontal, vertical, 70.0, 70.0)];
                [buttonImage setTag:i];

                [buttonImage setImage:[blaukypath objectAtIndex:i] forState:UIControlStateNormal];
                [buttonImage addTarget:self action:@selector(buttonImagePressed:) forControlEvents:UIControlEventTouchUpInside];
                [buttonImage setImage:[UIImage imageNamed:@"play.png"] forState:UIControlStateSelected];

                [myScrollView addSubview:buttonImage];

                horizontal = horizontal + 70.0 + 8.0;
            }

            [myScrollView setContentSize:CGSizeMake(320.0, vertical + 78.0)];

            // Do any additional setup after loading the view, typically from a nib.
            self.navigationItem.leftBarButtonItem = self.editButtonItem;

            UIBarButtonItem *done = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(insertNewObject:)];

            self.navigationItem.rightBarButtonItem = done;

            [self.myScrollView addSubview:image];
        }

        sqlite3_finalize(statement);
    }

    sqlite3_close(contactDB);
}
4

1 に答える 1

1

いくつかの観察:

  • テーブルからデータを読み取るループ内にスクロールビューの構築を配置しました。たとえば、データベースに 9 つの行がある場合、9 つのスクロールビューがあり、最初の画像は 1 つ、2 つ目は 2 つ、3 つ目は 3 つというように、合計 45 の画像になります。それがあなたの意図したことなのか、本当に疑わしいです。

  • データベースから文字列を読み取り (この時点では画像を作成しないでください...画像のパスを保存するだけです)、配列に値を入力する 1 つのループが必要です。その後、UI を構築する別のループ (理想的には、完全に別のルーチン) を持つことができます。UI をデータベースとのやり取りから分離する必要があります。また、画像オブジェクトの配列で構成されるものはすべて問題になります。画像パスの配列のみを維持してください。

必要のない大量の画像を作成するというこの問題は、間違いなくアプリの速度を低下させ、メモリを消費します。画像のサイズによっては、メモリが不足してクラッシュすることさえあります。

少なくとも、この問題に対処する必要があります。

追加の問題がいくつかあります。

  • クラッシュの別の潜在的な原因は、アレイ内のイメージ パスの 1 つがイメージのパスに解決されなかった場合です。したがって、 はimageWithContentsOfFileを返しnil、配列に追加しようとするnilとクラッシュします。イメージを使用する前に、イメージが正常に検出/ロードされたかどうかをテストして確認してください。

  • 画像のサイズについては言及されていませんが、140x140 を超える場合は、画面解像度のレンディションを作成することを検討する必要があります。画像が非常に大きい場合、70x70 でレンダリングできますが、完全な画像のためにメモリを使い果たします。また、これだけ多くの画像を同時に表示すると、画面解像度の画像の使用に注意しないと、すぐにメモリを消費してしまいます。

  • 配列内で参照する画像の数によっては、UIScrollViewDelegateメソッドを処理し、オブジェクトscrollViewDidScrollのみを作成し、スクロールして表示されるときにUIImageViewそれぞれimageのプロパティを設定するモデルを検討することもできます (スクロールして表示されなくなったものは削除します)。iOS 6 を対象とする場合UICollectionViewは、手動で生成したスクロールビューの代わりに を使用でき、その機能の一部を自動的に取得できます (配列が画像パスの配列であり、画像オブジェクトの配列ではない場合)。

それでもクラッシュする場合は、クラッシュの詳細をお知らせください (発生した例外/エラーの種類を教えていただけない場合は、推測にすぎません)。また、まだ実装していない場合はdidReceiveMemoryWarning、問題を特定して解決できるように、メモリ警告が発生したときに通知する を実装してください。また、このようなメモリを大量に消費するアプリは、必ずデバイスでテストしてください。メモリ関連の問題は、シミュレーターでは発生しませんが、デバイスでは頭をもたげてくることが多いためです。


上記はクラッシュの問題に焦点を当てていますが、パフォーマンスに関する質問もしました。特に を使用しておらずUICollectionView、スクロールビューを手動で構築している場合は、これを非同期で行いたいと思うかもしれません。基本的な考え方は、UIImageオブジェクトを作成するバックグラウンド操作を行い、それをメイン キューのスクロール ビューに追加する UI タスクをディスパッチすることです (バックグラウンド キューで UI操作を行うことは決してないため)。そうすれば、ユーザーは画像が表示されている間にアプリの使用を開始できます。

ここで考慮すべき微妙な問題がいくつかあります (複数のスレッドでデータベースとの対話を行うには、慎重な実装が必要です。UI の更新がメイン キューで確実に行われるようにするなど)。それでもパフォーマンスの問題がある場合は、典型的な解決策。

それでも、最初にクラッシュを修正することに集中し、次にパフォーマンスの問題に対処します。

于 2013-04-08T18:25:58.463 に答える