2009-07-29 4 views
1

토글로 사용되는 세그먼트 화 된 컨트롤이 있습니다. 전환 할 때 테이블 뷰에서 많은 내용을 전환합니다 (테이블 뷰에서 섹션 삽입/삭제, 변경 사항 애니 메이팅 등). 분할 된 컨트롤이 선택 항목에 즉시 응답하기를 원합니다. 분할 컨트롤의 UIControlEventValueChanged 이벤트 처리 코드 내 행동 그래서, 나는 다음을 수행하십시오UISegmentedControl (다른 것들 중에서도) 응답 가능 유지

- (IBAction)groupingChanged:(id)sender { 
    UISegmentedControl *seg = sender; 
    [tableModel toggleOn:[seg selectedSegmentIndex] == ToggleOnIndex]; 
    [self performSelectorOnMainThread:@selector(updateGrouping) 
          withObject:nil 
         waitUntilDone:NO]; 
} 

updateGrouping은 여기서

waitUntilDone:NO 설정
- (void)updateGrouping { 
    MXAssertMainThread(); 

    [tableView beginUpdates]; 
    ... several table updates 
    [tableView endUpdates]; 
} 

updateGrouping가 호출되기 전에 groupingChanged 방법을 완료 할 수 있습니다, 그러나 이것은보기를 다시 그리기에 충분하지 않은 것 같습니다. 세분화 된 컨트롤은 테이블 업데이트가 완료 될 때까지 계속 스틱되어 전환됩니다.

그래서 나는 그렇게 같은 업데이트 스레드를 만들 수 groupingChanged: 수정 시도 :

- (void)delayed { 
    [self performSelectorOnMainThread:@selector(updateGrouping) 
          withObject:nil 
         waitUntilDone:NO]; 
} 

- (IBAction)groupingChanged:(id)sender { 
    UISegmentedControl *seg = sender; 
    [tableModel toggleOn:[seg selectedSegmentIndex] == ToggleOnIndex]; 
    [self performSelectorInBackground:@selector(delayed) withObject:nil]; 
} 

을 그리고이 작업을 수행합니다. 세분화 된 컨트롤이 즉시 전환되고 테이블이 곧 따라옵니다. 그러나 결과에 대한 확신이 전혀 없습니다. 새 스레드가 시작되는 동안 주 스레드에게 유예 기간을 부여하는 부작용입니까? UI 업데이트를 큐에 저장하는 방법일까요? 분명히 해커 야. 나는 누군가가이 상황에 대해 그들이 따르고있는 더 좋은 패턴을 가지고 있기를 바라고있다.

답변

1

세그먼트 화 된 컨트롤이 실제로 다시 칠해 지는지 확인하려면 스레드로 들어가서는 안됩니다.

대신 0.1과 같은 낮은 값의 타이머를 설정하면 사용자에게 눈에 띄는 지연없이 컨트롤을 업데이트 할 수있을만큼 충분해야합니다.

많은 작업이 있지만 빠른 UI 업데이트가 필요한 경우이 기능을 사용했습니다.

여전히 조금 "해킹"되었지만 스레드가 도입되지 않았습니다.

그래서 ... 이런 식의

- (IBAction)groupingChanged:(id)sender { 
    UISegmentedControl *seg = sender; 
    [tableModel toggleOn:[seg selectedSegmentIndex] == ToggleOnIndex]; 
    [NSTimer scheduledTimerWithTimeInterval:0.1 
            target:self 
            selector:@selector(updateGrouping) 
            userInfo:nil 
            repeats:NO];  

} 
+0

중간 스레드를 제거하므로 개선되었지만 일반적으로 해킹되지 않는 패턴이 없다고 생각하지 않습니다. –

+0

performSelector : withObject : afterDelay는 Kendall이 지적한대로 유효합니다. 이 문제는 UI를 업데이트 할 수 있도록 실행 루프를 완료해야한다는 것입니다. 실제로 해킹이 아니라이 사실을 인정하는 것입니다. 어쨌든 주 스레드가 그 과정을 실행하는 것을 허용하지 않으면 서 UI를 업데이트하는 방법을 알지 못합니다. –

+0

물론, 나는 그 원인을 깨닫습니다. 나는 이것에 대한 공통적 인 패턴을 기대하고 있었다고 생각한다. 크레딧은 (뒤늦게) 수여됩니다. –

2

생각해 - 당신이하는 모든 일이 일반적으로 UI 업데이트를 포함하여, 주 스레드에서 수행된다.

그래서 원래 코드에서 세그먼트에 대한 UI 업데이트를 수행 한 코드보다 먼저 테이블보기를 업데이트 한 코드에 도달했습니다.

그래서 메인 스레드가 백그라운드 스레드가 테이블 업데이트를 처리하는 동안 주 스레드가 UI 업데이트를 완료 할 수 있었기 때문에 주 스레드에 휴식 시간을 허용하면 UI 업데이트를 완료하는 데 더 많은 시간이 허용되었습니다.

대신에 performSelector : withObject : afterDelay를 0.0 지연 (주 스레드가 선택기로 진행하기 전에 다른 작업을 처리 할 수있게 함)을 사용하는 것이 좋습니다. performSelectorOnMainThread가 작동하지 않는 곳에서 작동 할 수도 있습니다. 그 이유는 매우 유사한 작업을 수행하더라도 더 빨리 호출 할 수 있기 때문입니다.

0

같은 문제가 발생하여 UISegmentedControl의 하위 클래스를 만들어 지연된 UISegmentedControl을 만들었습니다.

지연된 제어에서는 addTarget:action:forControlEvents:을 오버로드하여 대상을 캡처합니다 (& 조치). 그런 다음 세그먼트 이벤트가 발생할 때 NSTimer을 실행하여 설정된 지연 후에 캡처 된 대상 & 동작을 시작합니다. 결과는 UI 세그먼트 클릭 표시 업데이트되는 것입니다 그리고 내가하고자했다 UISegmentedControl처럼 DelayedUISegmentedControl를 사용할 수 있습니다

// Follows all normal initialization patterns of UISegmentedControl 
UISegmentedControl *segmentedControl = [[DelayedUISegmentedControl alloc] 
    initWithItems:[NSArray arrayWithObjects: @"First", @"Second", nil]]; 

// Adds a delay to the selector; default is 0.25 
[segmentedControl addTarget:self action:@selector(segmentAction:) 
    forControlEvents:UIControlEventValueChanged]; 

을 당신은 내가 공개 google code에이를 공급 한 컨트롤을 다운로드합니다.

관련 문제