2012-05-28 3 views
3

CALayer의 displaydrawInContext과 관련된 내용은보기에 drawRect과 관련이 있습니다.iOS에서 setNeedsDisplay는 실제로 drawRect를 호출하지 않습니다 ... CALayer의 표시 또는 drawInContext가 마지막으로 drawRect를 호출하지 않는 한?

NSTimer가 [self.view setNeedsDisplay]을 1 초로 설정하면 drawRect의 NSLog 문에 표시된 것처럼 drawRect이 1 초마다 호출됩니다.

그러나 CALayer를 서브 클래스 화하여 뷰에 사용하면 display 메서드를 비워두면 지금은 drawRect이 호출되지 않습니다. 업데이트 : 그러나 NSLog 문에 표시된 것처럼 display은 1 초마다 호출됩니다.

display 메서드를 제거하고 빈 drawInContext 메서드를 추가하면 drawRect이 호출되지 않습니다. 업데이트 : 그러나 NSLog 문에 표시된 것처럼 drawInContext은 1 초마다 호출됩니다.

정확히 무엇이 일어나고 있습니까? displaydrawInContextdrawInContext을 선택적으로 호출 할 수 있으며 어떻게 든 drawRect (어떻게?)을 호출 할 수 있지만 실제로 상황은 무엇입니까?


업데이트 :

나는 다음에 CoolLayer.m 코드를 변경 : 대답 더 많은 단서가 달이있는 경우

-(void) display { 
    NSLog(@"In CoolLayer's display method"); 
    [super display]; 
} 

-(void) drawInContext:(CGContextRef)ctx { 
    NSLog(@"In CoolLayer's drawInContext method"); 
    [super drawInContext:ctx]; 
} 

을 따라서는, (의 말을하자 보기에서 위치 (100,100)에서 Core Graphics에 의해 그려진 원으로), 이제 위치 (200,200)로 변경하고, 당연히 [self.view setNeedsDisplay]으로 전화 할 것이고, 이제 CALayer는 새로운 뷰 이미지 , 나의 ..로써 drawRect은 달이 지금 어떻게 표시되어야 하는지를 지시합니다.

는 그럼에도 불구하고, 시작점의 CALayer의 display 다음의 CALayer의 drawInContext이다 : 나는 drawRect에서 브레이크 포인트를 설정하면 호출 스택을 보여줍니다

enter image description here

그래서 우리가 CoolLayer의 display는 것을 알 수 있습니다 처음 입력하면 CALayer의 display으로 이동 한 다음 CoolLayer의 drawInContext으로 이동 한 다음 CALayer의 drawInContext으로 이동합니다.이 경우 새 이미지에 대해 캐시가 존재하지 않습니다.

마지막으로 CALayer의 drawInContext은 대표자의 drawLayer:InContext을 호출합니다. 위임은 뷰 (FooView 또는 UIView) ...이고 drawLayer:InContext은 UIView의 기본 구현입니다 (필자가 무시하지 않았으므로). 마지막으로 drawLayer:InContextdrawRect입니다.

그래서 두 가지 점을 짐작할 수 있습니다. 이미지 캐시가 없어도 왜 CALayer를 입력합니까? 이 메커니즘을 통해 이미지가 컨텍스트에서 그려지고 마지막으로 display으로 돌아가고이 컨텍스트에서 CGImage가 만들어지면 이제 캐시 된 새 이미지로 설정됩니다. 이것이 CALayer가 이미지를 캐싱하는 방법입니다.

또 다른 사실은 확실하지 않습니다. [self.view setNeedsDisplay] 항상 drawRect을 호출하면 CALayer의 캐시 된 이미지를 사용할 수 있습니까? 맥 오에스 텐에서 다른 창문이 창문을 덮을 때, 그리고 맨 위 창문이 사라져 버렸다. 이제 모든 것을 다시 그리기 위해 drawRect을 호출 할 필요는 없지만 CALayer에서 캐시 된 이미지를 사용할 수 있습니다. 또는 iOS에서 앱을 중지하고 다른 작업을 수행 한 다음 다시 앱으로 돌아 오면 drawRect 대신에 캐시 된 이미지를 사용할 수 있습니다. 그러나 이러한 두 가지 유형의 "더러운"을 구별하는 방법은 무엇입니까? 하나는 "알려지지 않은 더러운"입니다 - 달은 drawRect 논리에 의해 지시 된대로 다시 그려야합니다 (좌표에는 임의의 숫자도 사용할 수 있습니다). 더러운 다른 유형은 은폐되었거나 사라지게되었고, 이제 다시 표시해야합니다.

답변

1

UIView의 업데이트 절차는 dirty 상태를 기반으로하므로 모양이 변경되지 않으면보기가 다시 그려지 지 않습니다.

개발자 참조에서 언급 한 내부 구현입니다.

+0

어떻게 CALayer가 작동합니까? –

+0

문서에서'setNeedsDisplay'는 UIKit과 Core Graphics 도면들에 대해서만 작동한다고 명시 적으로 언급되었으므로, 더티 뷰 업데이트는 둘 다 유효합니다. 설명서에는 'CAEAGLLayer'가 유효하지 않으므로주의해야합니다. –

+0

우리가'setNeedsDisplay'를 사용하지만 CALayer의 메서드를 오버라이드하면'drawRect'가 호출되지 않고 그 이유는 무엇입니까? –

12

레이어가 표시되어야하고 유효한 백킹 저장소가없는 경우 (레이어가 setNeedsDisplay 메시지를 수신했기 때문에) 시스템에서 display 메시지를 레이어로 보냅니다.

-[CALayer display] 방법은 다음과 같이 대략 같습니다 그래서

- (void)display { 
    if ([self.delegate respondsToSelector:@selector(displayLayer:)]) { 
     [[self.delegate retain] displayLayer:self]; 
     [self.delegate release]; 
     return; 
    } 

    CABackingStoreRef backing = _backingStore; 
    if (!backing) { 
     backing = _backingStore = ... code here to create and configure 
      the CABackingStore properly, given the layer size, isOpaque, 
      contentScale, etc. 
    } 

    CGContextRef gc = ... code here to create a CGContext that draws into backing, 
     with the proper clip region 
    ... also code to set up a bitmap in memory shared with the WindowServer process 

    [self drawInContext:gc]; 
    self.contents = backing; 
} 

, 당신은 display을 무시할 경우 [super display]를 호출하지 않는 한, 그 어느 것도 발생하지 않습니다. FooViewdisplayLayer:을 구현하는 경우 자신 만의 CGImage을 만들고 레이어의 속성에 저장해야합니다.

-[CALayer drawInContext:] 방법은 다음과 거의 같습니다

- (void)drawInContext:(CGContextRef)gc { 
    if ([self.delegate respondsToSelector:@selector(drawLayer:inContext:)]) { 
     [[self.delegate retain] drawLayer:self inContext:gc]; 
     [self.delegate release]; 
     return; 
    } else { 
     CAAction *action = [self actionForKey:@"onDraw"]; 
     if (action) { 
      NSDictionary *args = [NSDictionary dictionaryWithObject:gc forKey:@"context"]; 
      [action runActionForKey:@"onDraw" object:self arguments:args]; 
     } 
    } 
} 

onDraw 작업은 내가 아는 한 문서화되어 있지 않습니다.

-[UIView drawLayer:inContext:] 방법은 다음과 거의 같습니다

- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)gc { 
    set gc's stroke and fill color spaces to device RGB; 
    UIGraphicsPushContext(gc); 
    fill gc with the view's background color; 
    if ([self respondsToSelector:@selector(drawRect:)]) { 
     [self drawRect:CGContextGetClipBoundingBox(gc)]; 
    } 
    UIGraphicsPopContext(gc); 
} 
+0

에 대한 도움으로 +1, 어떻게 알 수 있습니까? 소스 코드를 읽거나 그냥 추측을합니까? –

+4

호퍼를 사용하여 IOS 시뮬레이터 라이브러리를 분해했습니다. –

0

가 drawInContext 또는 디스플레이를 구현 또는 뷰가 dirty 일 때의 drawRect 당신이 호출 할 일 (needsDisplay를) OS를 알려줍니다. 더티 뷰에 대해 호출 할 코드를 선택하고 구현하고 다른 코드에서 실행되도록 코드를 작성하지 마십시오.

관련 문제