2012-05-07 29 views
9

Tôi đang làm việc trên một ứng dụng vẽ có sử dụng CoreGraphics để hiển thị. Vấn đề của tôi là, đối với hiệu suất, tôi đang cố gắng giới hạn các bản cập nhật cho chỉ một số phần nhất định của chế độ xem đã thay đổi. Đối với điều đó, tôi sử dụng setNeedsDisplayInRect :, nhưng đôi khi chế độ xem cập nhật toàn bộ nội dung của nó, gây gián đoạn. Điều này đặc biệt rõ ràng trên iPad thế hệ thứ 3, nhưng nó cũng xảy ra trong trình mô phỏng và iPad2 ở mức độ thấp hơn. Tôi đang cố xóa hành vi này.setNeedsDisplayInRect: làm cho toàn bộ chế độ xem được cập nhật

Để hiển thị sự cố, tôi đã tạo một dự án "xem đơn" đơn giản bằng cách sử dụng mẫu trong Xcode. Đã tạo lớp con UIView tùy chỉnh mà tôi đặt làm chế độ xem của trình điều khiển chế độ xem trong tệp xib.

gia tăng này đến UIViewController:

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    // Asks that the view refreshes a smal rectangle 
    [self.view setNeedsDisplayInRect:CGRectMake(10, 10, 20, 20)]; 
} 

gia tăng này đến MyView (xem tùy chỉnh của tôi):

- (void)drawRect:(CGRect)rect 
{ 
    // Just log what is being updated 
    NSLog(@"%@", NSStringFromCGRect(rect)); 
} 

Và đó là nó. Nếu tôi chạy ứng dụng trên iPad thứ 10 (thiết bị thực tế), nhật ký hiển thị chế độ xem tự vẽ lại trong entierty của nó theo thời gian (như thường xuyên). Điều này thật khó chịu và tôi không biết ý tưởng

CẬP NHẬT: Dưới đây là một số nhật ký. Nó chắc chắn cho thấy xem đầy đủ được cập nhật đôi khi. Tôi cố gắng để làm cho nó dừng lại hoàn toàn nhưng không thể tìm cách ...

2012-05-04 08:34:01.851 TestUpdateArea[45745:707] {{0, 0}, {320, 460}} 
2012-05-04 08:34:30.184 TestUpdateArea[45745:707] {{0, 0}, {320, 460}} 
2012-05-04 08:34:30.197 TestUpdateArea[45745:707] {{0, 0}, {320, 460}} 
2012-05-04 08:34:30.215 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.226 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.242 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.258 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.274 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.290 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.306 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.322 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.338 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.354 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.371 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.387 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.403 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.419 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:30.439 TestUpdateArea[45745:707] {{0, 0}, {320, 460}} 
2012-05-04 08:34:30.457 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 

Ngoài ra nếu tôi ngừng chuyển động trong hơn 10s hoặc lâu hơn và sơ yếu lý lịch, nó chắc chắn có phải nó rất nhất quán:

2012-05-04 08:34:33.305 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:34:33.321 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
2012-05-04 08:35:00.202 TestUpdateArea[45745:707] {{0, 0}, {320, 460}} 
2012-05-04 08:35:00.221 TestUpdateArea[45745:707] {{0, 0}, {320, 460}} 
2012-05-04 08:35:00.234 TestUpdateArea[45745:707] {{0, 0}, {320, 460}} 
2012-05-04 08:35:00.251 TestUpdateArea[45745:707] {{10, 10}, {20, 20}} 
+0

Trong trường hợp của tôi, khi drawRect gọi sau khi setNeedsDisplayInRect ** lần đầu tiên **, rect là giới hạn đầy đủ (không hỏi lý do của tôi), bất kỳ cuộc gọi tiếp theo nào chính xác là rect tôi đã chỉ định làm tham số trong setNeedsDisplayInRect. Bạn đã kiểm tra cảm ứng di chuyển nhiều lần? –

+0

Nó xảy ra chủ yếu trên thiết bị trực tiếp. Nhưng bạn có thể làm cho nó xảy ra trên giả lập nếu bạn di chuyển ngón tay của bạn xung quanh và sau đó chờ khoảng 10 hoặc 15 giây, sau đó chạm và di chuyển một lần nữa. Trên thiết bị iPad3, nó xảy ra ngay cả khi ngón tay đang di chuyển. Sooo gây phiền nhiễu :) – mprivat

+0

Tôi đăng @ này một lúc trở lại (http://stackoverflow.com/questions/9299018/setneedsdisplayinrect-bug-in-ios5). Dường như chỉ là cuộc gọi đầu tiên. Tôi chưa bao giờ tìm thấy nguyên nhân/sửa chữa và chỉ tiếp tục vì tôi không cần mức tối ưu hóa hiệu suất đó.Bạn có thể kiểm tra kích thước xem rect == và không vẽ không? Có lẽ không phải là một lựa chọn. –

Trả lời

5

Kiểm tra táo này document

họ nói:

vì cách mà iPhone/iPod touch/iPad upda màn hình của nó, chế độ xem toàn bộ sẽ được vẽ lại nếu bạn gọi -setNeedsDisplayInRect: hoặc -setNeedsDisplay:.

Cũng

Mỗi UIView được coi là một yếu tố duy nhất. Khi bạn yêu cầu vẽ lại, một phần hoặc toàn bộ, bằng cách gọi -setNeedsDisplayInRect: hoặc -setNeedsDisplay:, toàn bộ chế độ xem sẽ được đánh dấu để cập nhật.

vì vậy, tôi nghĩ bạn cần sử dụng các bản xem trước để cập nhật trực tiếp độc lập toàn bộ Chế độ xem.

+1

Điều đó không có ý nghĩa. Điều gì sẽ là điểm trong việc có hai phương pháp sau đó. Và tại sao nó chỉ làm việc đôi khi? – mprivat

+0

Tôi đã đọc một số lỗi trong iOS 5 .. bạn đã thử trên iOS 4 chưa? –

+0

Nó làm điều đó trong iOS4 đến một mức độ thấp hơn nhiều. – mprivat

0

Tôi có một vấn đề tương tự: cụ thể là muốn cập nhật chỉ một phần của UIView với một cuộc gọi đến setNeedsDisplayInRect: tôi vượt qua một CGRect hợp lệ có kích thước chính xác (được chứng minh bằng Điểm Break và Nhật ký). Theo iOS 4.2.1 (trên iPhone 3G của tôi) UIView giữ nguyên hình ảnh gốc và chỉ cập nhật phần được chỉ định bởi CGRect, nhưng dưới iOS 5.1 (trên iPhone 4S) toàn bộ UIView được vẽ lại màu đen trong suốt (màu đen có thể minh bạch là vượt ra ngoài tôi), với khu vực được chỉ định bởi CGRect được rút ra một cách chính xác sau. Nó có vẻ là một trong hai: một lỗi trên một phần của Apple rằng họ không thực hiện setNeedsDisplayInRect: chính xác và chỉ cần chuyển nó đến setNeedsDisplay :; hoặc đó là một quyết định cố ý dựa trên cách iOS mới xử lý tương tác với kiến ​​trúc màn hình thực tế.Dù bằng cách nào, có vẻ như trong thời gian các nhà phát triển sẽ phải trả chi phí cập nhật toàn bộ UIView mỗi khi thay đổi đồ họa xảy ra hoặc sử dụng một số phát hiện iOS và triển khai mã vẽ màn hình khác nhau tùy thuộc vào iOS đang được xử lý.

Tôi đã thực hiện một số thử nghiệm với thuộc tính UIView clearsContextBeforeDrawing (theo tài liệu nên cho phép thao tác vẽ được nhắm mục tiêu), nhưng kết quả giống hệt nhau cho cả YES và NO, vì vậy có vẻ như việc triển khai mã vẽ .

Đối với CGRect có kích thước không chính xác trong khi cập nhật: nó đang được đặt ở nơi khác trước hoặc sau cuộc gọi vẽ. Tôi đặt CGRect của tôi ngay trước khi cuộc gọi đến setNeedsDisplayInRect :, và sau đó đặt nó thành CGRectNull trên một vài dòng cuối cùng của phương thức drawRect (điều này là như vậy nếu phương thức drawRect được gọi bởi hệ thống mã của tôi sẽ không kích hoạt). Sau khi quay trở lại đoạn mã của bạn, tôi có thể nhìn thấy nó được thiết lập trong dòng, có nghĩa là đó là một cuộc gọi hệ thống vẽ lại toàn bộ UIView, và do đó CGRect là toàn bộ khung nhìn.

Tôi sẽ tiếp tục đào sâu vào điều này, nhưng tôi sợ rằng cho đến khi Apple tiết lộ lý do của họ về thay đổi để thiết lậpNeedsDisplayInRect :, hoặc sửa lỗi rõ ràng, chúng tôi có thể xem xét cập nhật toàn bộ nội dung của UIView cho mọi đồ họa cập nhật (có thể có khả năng rất 'đắt tiền').

+0

Đó là điều tôi sợ. Tôi đã mở một vé hỗ trợ kỹ thuật với Apple và họ âm thầm đóng nó và ghi lại chi phí vé vào tài khoản của tôi mà không nói một từ ... – mprivat

13

Câu trả lời được chấp nhận sai (hoặc ít nhất là gây hiểu lầm).

Dưới đây là một ví dụ mã đơn giản của setNeedsDisplayInRect: làm việc như đã quảng cáo:

http://charcoaldesign.co.uk/resources/chalkboard.zip

tôi nghi ngờ rằng các tài liệu của Apple đang cố gắng để giải thích thực tế là trên iOS mỗi hình ảnh xem ủng hộ được chuyển thành một kết cấu OpenGL và toàn bộ màn hình được tổng hợp lại mỗi khung hình. Điều đó khác với câu hỏi liệu mã của bạn có phải xóa và vẽ lại toàn bộ nội dung của kết cấu sao lưu của chế độ xem hay không.

Bằng cách sử dụng setNeedsDisplayInRect: bạn có thể tránh vẽ lại nội dung tốn kém không thay đổi giữa các khung (sử dụng đồ họa lõi và không tăng tốc phần cứng). Toàn bộ màn hình sẽ vẫn được vẽ lại bất kể, nhưng điều đó không quan trọng vì phần cứng của nó được tăng tốc bởi GPU, không giống như mã trong drawRect:

0

Tôi không có nhiều thiết bị sẵn có, nhưng tôi có tin tức nào! Là một người có nhu cầu về chức năng này trên iOS trong nhiều năm, tôi có thể khẳng định rằng iOS8.0 + mang chức năng này. Tôi đã thử trên cả trình mô phỏng và thiết bị cho 8.0, 8.1, 8.2

Tôi chưa thử tính năng này từ iOS6. Vì vậy, tôi không chắc chắn nếu nó có sẵn trong iOS7 hay không. Có lẽ ai đó khác có thể xác nhận.

Vui lòng tham gia cùng tôi để cổ vũ vô tận cho setNeedsDisplayInRect: hoạt động như được ghi lại!

Các vấn đề liên quan