2013-06-11 40 views
23

Tôi cố gắng để sử dụng CAShapeLayer để che dấu một CALayer trong ứng dụng iOS của tôi như là phải mất một phần nhỏ của CPU time để che dấu một hình ảnh vs tay che một trong một bitmap context;vấn đề hiệu suất Khi sử dụng Nhiều Mặt nạ CALayer

Khi tôi có nhiều chục ảnh trở lên được xếp chồng lên nhau, CAShapeLayer đeo mặt nạ UIImageView sẽ chậm chạp để di chuyển đến liên lạc của tôi.

Dưới đây là một số mã ví dụ:

UIImage *image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle]pathForResource:@"SomeImage.jpg" ofType:nil]]; 
CGMutablePathRef path = CGPathCreateMutable(); 
CGPathAddEllipseInRect(path, NULL, CGRectMake(0.f, 0.f, image.size.width * .25, image.size.height * .25)); 

for (int i = 0; i < 200; i++) { 

    SLTUIImageView *imageView = [[SLTUIImageView alloc]initWithImage:image]; 
    imageView.frame = CGRectMake(arc4random_uniform(CGRectGetWidth(self.view.bounds)), arc4random_uniform(CGRectGetHeight(self.view.bounds)), image.size.width * .25, image.size.height * .25); 

    CAShapeLayer *shape = [CAShapeLayer layer]; 
    shape.path = path; 
    imageView.layer.mask = shape; 

    [self.view addSubview:imageView]; 
    [imageView release]; 

} 
CGPathRelease(path); 

Với đoạn mã trên, imageView là rất lag. Tuy nhiên, nó phản ứng ngay lập tức nếu tôi che giấu nó bằng tay trong một bitmap context:

UIImage *image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle]pathForResource:@"3.0-Pad-Classic0.jpg" ofType:nil]]; 
CGMutablePathRef path = CGPathCreateMutable(); 
CGPathAddEllipseInRect(path, NULL, CGRectMake(0.f, 0.f, image.size.width * .25, image.size.height * .25)); 


for (int i = 0; i < 200; i++) { 

    UIGraphicsBeginImageContextWithOptions(CGSizeMake(image.size.width * .25, image.size.height * .25), NO, [[UIScreen mainScreen]scale]); 
    CGContextRef ctx = UIGraphicsGetCurrentContext(); 

    CGContextAddPath(ctx, path); 
    CGContextClip(ctx); 

    [image drawInRect:CGRectMake(-(image.size.width * .25), -(image.size.height * .25), image.size.width, image.size.height)]; 
    UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 

    SLTUIImageView *imageView = [[SLTUIImageView alloc]initWithImage:finalImage]; 
    imageView.frame = CGRectMake(arc4random_uniform(CGRectGetWidth(self.view.bounds)), arc4random_uniform(CGRectGetHeight(self.view.bounds)), finalImage.size.width, finalImage.size.height); 

    [self.view addSubview:imageView]; 
    [imageView release]; 

} 
CGPathRelease(path); 

Bằng cách này, đây là đoạn code để SLTUIImageView, nó chỉ là một lớp con đơn giản của UIImageView mà đáp ứng chạm (dành cho những ai đã tự hỏi) :

-(id)initWithImage:(UIImage *)image{ 

    self = [super initWithImage:image]; 
    if (self) { 
     self.userInteractionEnabled = YES; 
    } 
    return self; 
} 

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ 
    [self.superview bringSubviewToFront:self]; 
} 

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{ 

    UITouch *touch = [touches anyObject]; 
    self.center = [touch locationInView:self.superview]; 
} 

có thể bằng cách nào đó tối ưu hóa như thế nào CAShapeLayer được che UIImageView sao cho hiệu suất được cải thiện? Tôi đã cố gắng tìm ra nơi mà các cổ chai đang sử dụng Time Profiler trong Instruments, nhưng tôi không thể nói chính xác những gì đang gây ra nó.

Tôi đã thử đặt shouldRasterize thành YES trên cả hai layer và trên layer.mask nhưng dường như không có bất kỳ ảnh hưởng nào. Tôi không biết phải làm gì.

Edit:

Tôi đã làm thử nghiệm nhiều hơn và thấy rằng nếu tôi sử dụng chỉ là một thường xuyên CALayer để mặt nạ khác CALayer (layer.mask = someOtherLayer) Tôi có vấn đề hiệu suất tương tự. Dường như vấn đề không cụ thể đối với CAShapeLayer —rằng sự cố cụ thể đối với thuộc tính mask của CALayer.

Chỉnh sửa 2:

Vì vậy, sau khi tìm hiểu thêm về việc sử dụng Core Animation tool trong Instruments, tôi biết được rằng quan điểm đã được trả lại offscreen mỗi lần nó di chuyển. Đặt shouldRaster thành YES khi chạm vào bắt đầu và tắt khi chạm vào kết thúc khiến màn hình luôn ở màu xanh lá cây (do đó giữ bộ nhớ cache) trong instruments, nhưng hiệu suất vẫn còn khủng khiếp. Tôi tin rằng điều này là bởi vì mặc dù chế độ xem đang được lưu vào bộ nhớ cache, nếu nó không bị mờ, thì nó vẫn phải được hiển thị lại với mỗi khung hình.

Một điều cần nhấn mạnh là nếu chỉ có một vài chế độ xem bị che khuất (nói khoảng 10) hiệu suất là khá tốt. Tuy nhiên, khi bạn tăng điều đó lên 100 or more, hiệu suất sẽ chậm lại. Tôi tưởng tượng điều này là bởi vì khi một người di chuyển qua những người khác, tất cả họ đều phải được trả lại.

Kết luận của tôi là, Tôi có một trong hai tùy chọn.

Trước tiên, phải có cách nào đó để che dấu vĩnh viễn chế độ xem (hiển thị một lần và gọi nó là tốt).Tôi biết điều này có thể được thực hiện thông qua các đồ họa hoặc bitmap bối cảnh tuyến đường như tôi hiển thị trong mã ví dụ của tôi, nhưng khi một lớp mặt nạ xem của nó, nó sẽ xảy ra ngay lập tức. Khi tôi làm điều đó trong một bối cảnh bitmap như được hiển thị, nó là khá chậm (như trong nó gần như thậm chí không thể so sánh bao nhiêu chậm hơn nó được).

Thứ hai, phải có một số cách faster để thực hiện điều đó thông qua tuyến đường ngữ cảnh bitmap. Nếu có chuyên gia che giấu hình ảnh hoặc lượt xem, sự trợ giúp của họ sẽ được đánh giá rất nhiều.

+0

Đặt cược tốt nhất của bạn thực sự là nén 200 hình ảnh bạn đã thêm vào vòng lặp for trong 1 hình ảnh lớn bằng cách sử dụng một cái gì đó như mã được đề cập ở đây: http://stackoverflow.com/questions/4334233/how-to-capture- uiview-to-uiimage-without-loss-of-chất lượng-on-võng mạc-hiển thị Bạn cũng có thể thử sử dụng các công cụ và sử dụng trình thu thập thời gian để kiểm tra nơi nút cổ chai của mã của bạn. –

+0

Bạn đã thử hiển thị trước hình ảnh vào trạng thái cuối cùng cần thiết trước khi sử dụng chúng trong ứng dụng để ứng dụng không cần phải thực hiện tất cả quá trình xử lý đồ họa này, đặc biệt vì bạn có quá nhiều hình ảnh để thực hiện quá trình này chúng đang được di chuyển xung quanh vì vậy nó liên tục phải tái render tất cả chúng một cách liên tục. Tôi không chắc chắn nếu đó là một lựa chọn khả thi cho bạn và nếu bạn đã thử nó chưa. Nó cũng rất khó để nắm bắt những gì bạn đang cố gắng để làm với những hình ảnh mà không có một hình ảnh, trong trường hợp này điều quan trọng là, nếu bạn đính kèm một ảnh chụp màn hình nó sẽ giúp đỡ. –

+1

Điều này là do hiển thị offscreen như bạn đã chỉ ra. Tôi không nghĩ rằng có một cách để tối ưu hóa hiệu suất về lớp, nhưng như bạn đã thấy bạn có thể tối ưu hóa quá trình. Một bước xa hơn có thể được phân lớp UIView ghi đè drawRect để đạt được những gì bạn cần. DrawRect được gọi chỉ khi xem của bạn được đánh dấu là bẩn. Không phân lớp UIImageView bacuse drawRect không bao giờ được gọi. – Andrea

Trả lời

1

Bạn đã nhận được khá xa và tôi tin rằng gần như là một giải pháp. Những gì tôi sẽ làm chỉ đơn giản là một phần mở rộng của những gì bạn đã thử. Vì bạn nói nhiều lớp trong số này là "kết thúc" ở các vị trí cuối cùng không đổi liên quan đến các lớp khác và mặt nạ. Vì vậy, chỉ cần hiển thị tất cả các lớp "đã hoàn thành" đó thành một ngữ cảnh bitmap duy nhất. Bằng cách đó, mỗi lần bạn viết ra một lớp cho bối cảnh đơn lẻ đó, bạn sẽ có một lớp ít hơn để lo lắng về việc đó đang làm chậm quá trình hoạt ảnh/kết xuất.

0

Quartz (drawRect :) chậm hơn CoreAnimation vì nhiều lý do: CALayer vs CGContextdrawRect vs CALayer. Nhưng nó là cần thiết để sử dụng nó một cách chính xác.

Trong tài liệu, bạn có thể thấy một số lời khuyên. ImprovingCoreAnimationPerformance

Nếu bạn muốn có hiệu suất cao, có thể bạn có thể thử sử dụng AsyncDisplayKit. Khuôn khổ này cho phép tạo các ứng dụng mượt mà và đáp ứng.