在应用启动时打开大型子文件,导致较长的开始时间

时间:2015-07-13 13:26:03

标签: ios json xcode

我正在创建一个由不同游戏板组成的游戏,这些游戏板作为字典存储在一个数组中,存储在json文件中。 json文件非常大,数组中有超过3,000个对象,大小约为23mb。我此刻加载此文件的方式是在appDelegate实现文件中的didFinishLaunchingWithOptions中,如下所示:

NSString * filePath =[[NSBundle mainBundle] pathForResource:@"words" ofType:@"json"];

NSError * error;
NSString* fileContents =[NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&error];


if(error)
{
    NSLog(@"Error reading file: %@",error.localizedDescription);
}


NSDictionary *data = (NSDictionary *)[NSJSONSerialization
                                      JSONObjectWithData:[fileContents dataUsingEncoding:NSUTF8StringEncoding]
                                      options:0 error:NULL];

wordsArray = [[NSMutableArray alloc]initWithArray:[data objectForKey:@"results"]];

然后我可以通过调用:

从应用程序的任何位置检索数组
NSArray *wordsArray = appDelegate.wordsArray;

除了应用程序在iPhone 4设备上加载花费超过15秒这太长时间之外,它的效果很好,而且我知道应用程序可能因为加载时间过长而被拒绝。

有人可以提出一个更好的方法来解决这个问题,

感谢

5 个答案:

答案 0 :(得分:3)

使用核心数据之类的东西。它专为存储此类信息而设计。

另外,不要把它交给APP代表!应用程序代表可以响应应用程序事件。它不是您的应用所需的所有数据的转储。

答案 1 :(得分:2)

设置带有加载程序的输入屏幕(为用户做一个有趣的加载程序......)并在此屏幕上加载数据。完成后,启动游戏......

答案 2 :(得分:2)

根据Yedidya的建议,您可能希望展示一些有趣的内容以保持用户参与。

最重要的是,最重要的是:

  • 保持您的用户界面响应
  • 在后台线程上加载文件/网络资源。有充足的代码示例显示相同。使用public Bitmap compressImage(String imageUri) { String filePath = imageUri; // String filePath = getRealPathFromURI(imageUri); Bitmap scaledBitmap = null; BitmapFactory.Options options = new BitmapFactory.Options(); // by setting this field as true, the actual bitmap pixels are not // loaded in the memory. Just the bounds are loaded. If // you try the use the bitmap here, you will get null. options.inJustDecodeBounds = true; Bitmap bmp = BitmapFactory.decodeFile(filePath, options); int actualHeight = options.outHeight; int actualWidth = options.outWidth; // max Height and width values of the compressed image is taken as // 816x612 /* * float maxHeight = 816.0f; float maxWidth = 612.0f; */ float maxHeight = 1080.0f; float maxWidth = 800.0f; float imgRatio = actualWidth / (float) actualHeight; float maxRatio = maxWidth / (float) maxHeight; // width and height values are set maintaining the aspect ratio of the // image if (actualHeight > maxHeight || actualWidth > maxWidth) { if (imgRatio < maxRatio) { imgRatio = maxHeight / actualHeight; actualWidth = (int) (imgRatio * actualWidth); actualHeight = (int) maxHeight; } else if (imgRatio > maxRatio) { imgRatio = maxWidth / actualWidth; actualHeight = (int) (imgRatio * actualHeight); actualWidth = (int) maxWidth; } else { actualHeight = (int) maxHeight; actualWidth = (int) maxWidth; } } // setting inSampleSize value allows to load a scaled down version of // the original image options.inSampleSize = calculateInSampleSize(options, actualWidth, actualHeight); // inJustDecodeBounds set to false to load the actual bitmap options.inJustDecodeBounds = false; // this options allow android to claim the bitmap memory if it runs low // on memory options.inPurgeable = true; options.inInputShareable = true; options.inTempStorage = new byte[16 * 1024]; try { // load the bitmap from its path bmp = BitmapFactory.decodeFile(filePath, options); } catch (OutOfMemoryError exception) { exception.printStackTrace(); } try { scaledBitmap = Bitmap.createBitmap(actualWidth, actualHeight, Bitmap.Config.ARGB_8888); } catch (OutOfMemoryError exception) { exception.printStackTrace(); } float ratioX = actualWidth / (float) options.outWidth; float ratioY = actualHeight / (float) options.outHeight; float middleX = actualWidth / 2.0f; float middleY = actualHeight / 2.0f; Matrix scaleMatrix = new Matrix(); scaleMatrix.setScale(ratioX, ratioY, middleX, middleY); Canvas canvas = new Canvas(scaledBitmap); canvas.setMatrix(scaleMatrix); canvas.drawBitmap(bmp, middleX - bmp.getWidth() / 2, middleY - bmp.getHeight() / 2, new Paint( Paint.FILTER_BITMAP_FLAG)); // check the rotation of the image and display it properly ExifInterface exif; try { exif = new ExifInterface(filePath); int orientation = exif.getAttributeInt( ExifInterface.TAG_ORIENTATION, 0); Log.d("EXIF", "Exif: " + orientation); Matrix matrix = new Matrix(); if (orientation == 6) { matrix.postRotate(90); Log.d("EXIF", "Exif: " + orientation); } else if (orientation == 3) { matrix.postRotate(180); Log.d("EXIF", "Exif: " + orientation); } else if (orientation == 8) { matrix.postRotate(270); Log.d("EXIF", "Exif: " + orientation); } scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, true); } catch (IOException e) { e.printStackTrace(); } return scaledBitmap; } performselectorOnBackground之一执行后台任务。
  • 完成后,使用dispatch_async(some_global_queue)performselectorOnMainThread返回主屏幕/游戏用户界面。

答案 3 :(得分:1)

Apple有许多指南可以帮助您:

通常,性能是App设计的产品,因此为了提高性能,您可能需要重新设计应用程序的大部分内容。

我会按照以下步骤操作:

  1. Instruments user Guide中测量CPU使用率和磁盘访问量。
  2. 不加载并解析主线程上的这么大的文件。
  3. 尽可能拆分文件。
  4. 如果应用中没有任何内容,请预加载资源。

答案 4 :(得分:1)

根据Yedidya的建议,您可能希望展示一些有趣的内容以保持用户参与。

最重要的是,最重要的是:

  • 保持您的用户界面响应
  • 在后台线程上加载文件/网络资源。有充足的代码示例显示相同。使用performselectorOnBackgrounddispatch_async(some_global_queue)之一执行后台任务。
  • 完成后,使用performselectorOnMainThreaddispatch_asynch(dispatch_get_main_queue)返回主屏幕/游戏用户界面。

这是要点:

    //START BUSY CURSOR HERE
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), 
    ^{
        // Read JSON file here
        dispatch_async(dispatch_get_main_queue(), 
      ^{
        //STOP BUSY CURSOR 
       //PERFORM UI UPDATE HERE
    });