2014-01-21 13 views
0

我有问题,我有一些非常大的UIScrollView和吨图像加载在用户滚动。图像存储在设备上,但是我从服务器接收信息要显示在UIScrollView的特定部分上。当用户滚动一下时,我需要在新的位置显示图像,因为我无法在启动时使用图像绘制整个UIScrollView。对于背景我有一个相对较小的图像,我在整个视图中移动。但问题是,在该背景之上,我应该绘制大量的UIImage对象(大约300-400),这些对象不是特别的bih,而是分层的(一个图像位于其他顶层)。在绘图时阻止滚动不是一种选择。准备有很多图层的背景线程的UIImage

现在我试图决定哪一种方法会适合我最好的:

  1. 添加所需的所有图像的UIView在后台线程,然后只需添加到UIView的滚动型的主线程(希望不会需要很长时间)。这里当滚动某处时,我需要计算并创建带有对象的新UIView,并将其放置在现有和可能的位置,以便在用户继续沿某个方向滚动时删除具有所有对象和图层的第一个UIView。

  2. 将图像中的所有图层与CoreGraphics相结合,并将它们呈现为已确定图层的对象。通过这种方式,我可以从滚动视图中移除特定对象(图像)。当用户滚动时,我只是创建新对象并将它们添加为以完整对象的形式查看,并且可以在用户滚动到足够的位置时删除对象,而不是删除整个视图。这里的问题是在主线程中向UIScrollView添加多个对象,但是当它们结合时它们不会超过15-20个对象。

我最关心的是性能和线程。正如我所说我不能阻止主线程(或者说让用户不会注意的时候不能这样做),并且不能将图像合并到我的图形部门,因为它们有很多变化,这些变化是在运行时决定的。这就是为什么我正在考虑一种在后台线程上准备数据的方法,并且只是在主线程上快速添加数据,而不是在主线程上准备和添加它(这会阻止UI)。

每一个帮助将大大appriciated!

问候,

hris.to

回答

0

看看使用CATiledLayer为一个UIView背衬。它是为此而设计的。

我有一个地图在UIScrollView中有一个UIView,而UIView的大小是整个地图的全部大小。 CATiledLayer处理何时绘制视图的每个图块。

+0

请不要使用堆栈溢出通过链接来推广你的网站;答案只应包括相关的代码,而不是其他网站的链接。 – LittleBobbyTables

+0

@LittleBobbyTables感谢您的领导!我一定不会再这样做。 –

0

好的,所以我在这里写,只是为了让你知道我如何解决我的问题。

主要问题是我在滚动时移动背景图片(所以我没有加载一个巨大的文件),同时这样做是从服务器获取信息并尝试在相同的图块上绘图,这会导致系统崩溃众所周知崩溃:

CALayer was muted while enumerated 

我得靠performSelector法@Synchronized一起,但事实证明,这不是有效的,有时两个线程(主UI线程和后台线程)正试图改变在屏幕上相同的瓷砖。所以基本上我所做的是改变背景提取和借鉴:

[self performSelectorOnBackgroundThread] 

使用混凝土后台线程,而我存储参考:每次我需要加载新的瓷砖

@property(nonatomic, strong) NSThread* backgroundThread; 

现在或者我需要移动背景,我在开始任何其他操作之前取消此线程(并确保它已取消)。也有与此线程和其他视图视图之间切换时,作为我危在旦夕一个小问题,我需要设置超时:

[_backgroundThread cancel]; 

int currentAttempts = 0; 
while([_backgroundThread isExecuting]) 
{ 
    if(currentAttempts == MAX_ATTEMPTS_TO_CANCEL_THREAD) 
    { 
     //make sure we dont hang and force background 
     _backgroundThread = nil; 
     return; 
    } 

    [_backgroundThread cancel]; 
    currentAttempts++; 
} 

在我的“scrollViewDidScroll”不过,我没有使用递归,因为这会在较旧的设备(如iPhone 4)上滚动时产生轻微的UI块,这是不可接受的。所以我基本上只是取消线程,并希望得到取消不够快(这与几十个测试似乎是工作):

- (void)scrollViewDidScroll:(UIScrollView*)scrollView 
{ 
    [_backgroundThread cancel]; 

    //move background around 
    [self moveBackground]; 
} 

这种方法的缺点是,你需要大量的检查在你的后台线程为呼叫'取消'实际上不会取消任何东西。根据苹果文档,它只会改变您的线程的isCancelled状态,您有责任使该线程以基本上与正常退出相同的方式退出(因此系统有机会在线程后清除):

if([_backgroundThread isCancelled]) 
{ 
    return; 
} 

问候,

hris.to