Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/103.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
ios5:drawRect在CATiledLayer中为同一个Rect调用了两次_Ios_Ios5_Catiledlayer - Fatal编程技术网

ios5:drawRect在CATiledLayer中为同一个Rect调用了两次

ios5:drawRect在CATiledLayer中为同一个Rect调用了两次,ios,ios5,catiledlayer,Ios,Ios5,Catiledlayer,我对CATiledLayer有问题。它在iOS 4上工作得很好,但在iOS 5上有问题 我的问题是,对于同一个rect,同时从两个不同线程调用两次drawRect。因为我在这个调用中加载了图像,所以导致视图加载非常慢 2011-10-18 14:07:18.802 APP[12436:19003] drawRect:{{0, 400}, {368, 400}} (view:<TiledScrollColumn: 0x91bc880; frame = (0 1600; 368 5400);

我对CATiledLayer有问题。它在iOS 4上工作得很好,但在iOS 5上有问题

我的问题是,对于同一个rect,同时从两个不同线程调用两次
drawRect
。因为我在这个调用中加载了图像,所以导致视图加载非常慢

2011-10-18 14:07:18.802 APP[12436:19003] drawRect:{{0, 400}, {368, 400}} (view:<TiledScrollColumn: 0x91bc880; frame = (0 1600; 368 5400); userInteractionEnabled = NO; layer = <CATiledLayer: 0x919c1b0>>)
2011-10-18 14:07:18.805 APP[12436:1b103] drawRect:{{0, 400}, {368, 400}} (view:<TiledScrollColumn: 0x91bc880; frame = (0 1600; 368 5400); userInteractionEnabled = NO; layer = <CATiledLayer: 0x919c1b0>>)
2011-10-1814:07:18.802应用[12436:19003]drawRect:{{0400},{3684000}(视图:)
2011-10-18 14:07:18.805应用[12436:1b103]drawRect:{{0400},{368400}(视图:)
有没有人知道是什么原因造成的,或者我能做些什么来解决这个问题?我没有对视图进行特殊处理,它基于photoscroller示例


巴斯蒂安

我找到了一个解决办法。创建一个串行(一次仅一个操作)调度队列并在其中执行所有绘图,然后缓存结果

我已经附加了我正在使用的代码,注意我使用的是
CATiledLayer
的子类,而不是通过委托或其他技术来绘制它

我还创建了一个不确定的磁贴缓存,这可能会导致内存问题,具体取决于您的情况。您可能需要管理缓存中的磁贴数量,在添加新磁贴时删除旧磁贴。当收到内存不足警告时,还应清除缓存。如果有人添加了这些改进,请随意编辑我的答案,将其包括在内

- (id)init
{
  if (!(self = [super init]))
    return nil;

  tileCache = [[NSMutableDictionary alloc] init];

  return self;
}

- (void)drawInContext:(CGContextRef)layerContext
{
  // CATiledLayer has a bug, where it spawns multiple threads for drawing, and then tries to draw the same tile multiple times simultaniously on separate threads
  // so we create our own serial background queue, and do dispatch_async on it. This will cache each draw operation, so multiple calls on one tile are efficient
  static dispatch_queue_t drawQueue = NULL;
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
      drawQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
  });

  dispatch_sync(drawQueue, ^{

    // no map ways? draw nothing
    if (!self.mapWays)
      return;

    // load from cache?
    CGRect tileRect = CGContextGetClipBoundingBox(layerContext);
    NSString *tileCacheKey = [NSString stringWithFormat:@"%f%f%f%f", tileRect.origin.x, tileRect.origin.y, tileRect.size.width, tileRect.size.height];
    __block UIImage *tileImage;
    dispatch_sync(dispatch_get_main_queue(), ^{
      tileImage = [tileCache objectForKey:tileCacheKey];
    });
    if (tileImage) {
      CGContextDrawImage(layerContext, tileRect, tileImage.CGImage);
      return;
    }

    // prepare to draw the tile image
    UIGraphicsBeginImageContextWithOptions(tileRect.size, YES, 0);
    CGContextRef context = UIGraphicsGetCurrentContext();

    // filp coords
    CGContextTranslateCTM(context, 0, tileRect.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);


    /*** do actual drawing here ***/


    // store tile in cache
    tileImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    dispatch_sync(dispatch_get_main_queue(), ^{
      [tileCache setObject:tileImage forKey:tileCacheKey];
    });

    // draw the tile
    CGContextDrawImage(layerContext, tileRect, tileImage.CGImage);
  });
}

我找到了一个解决办法。创建一个串行(一次仅一个操作)调度队列并在其中执行所有绘图,然后缓存结果

我已经附加了我正在使用的代码,注意我使用的是
CATiledLayer
的子类,而不是通过委托或其他技术来绘制它

我还创建了一个不确定的磁贴缓存,这可能会导致内存问题,具体取决于您的情况。您可能需要管理缓存中的磁贴数量,在添加新磁贴时删除旧磁贴。当收到内存不足警告时,还应清除缓存。如果有人添加了这些改进,请随意编辑我的答案,将其包括在内

- (id)init
{
  if (!(self = [super init]))
    return nil;

  tileCache = [[NSMutableDictionary alloc] init];

  return self;
}

- (void)drawInContext:(CGContextRef)layerContext
{
  // CATiledLayer has a bug, where it spawns multiple threads for drawing, and then tries to draw the same tile multiple times simultaniously on separate threads
  // so we create our own serial background queue, and do dispatch_async on it. This will cache each draw operation, so multiple calls on one tile are efficient
  static dispatch_queue_t drawQueue = NULL;
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
      drawQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
  });

  dispatch_sync(drawQueue, ^{

    // no map ways? draw nothing
    if (!self.mapWays)
      return;

    // load from cache?
    CGRect tileRect = CGContextGetClipBoundingBox(layerContext);
    NSString *tileCacheKey = [NSString stringWithFormat:@"%f%f%f%f", tileRect.origin.x, tileRect.origin.y, tileRect.size.width, tileRect.size.height];
    __block UIImage *tileImage;
    dispatch_sync(dispatch_get_main_queue(), ^{
      tileImage = [tileCache objectForKey:tileCacheKey];
    });
    if (tileImage) {
      CGContextDrawImage(layerContext, tileRect, tileImage.CGImage);
      return;
    }

    // prepare to draw the tile image
    UIGraphicsBeginImageContextWithOptions(tileRect.size, YES, 0);
    CGContextRef context = UIGraphicsGetCurrentContext();

    // filp coords
    CGContextTranslateCTM(context, 0, tileRect.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);


    /*** do actual drawing here ***/


    // store tile in cache
    tileImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    dispatch_sync(dispatch_get_main_queue(), ^{
      [tileCache setObject:tileImage forKey:tileCacheKey];
    });

    // draw the tile
    CGContextDrawImage(layerContext, tileRect, tileImage.CGImage);
  });
}

我认为您应该使用NSCache而不是NSMutableDictionary,这样它就可以为您处理内存问题。此外,这种方法似乎抵消了CATiledLayer的好处,因为这样做会将整个图像加载到内存中。我认为您可能希望使用NSCache而不是NSMutableDictionary,以便它为您处理内存问题。此外,这种方法似乎抵消了CATiledLayer的好处,因为这样做将把整个图像加载到内存中。