2017-04-24 3 views
0

UINavigationBarDelegate를 구현하려고하는데 사용자가이 뷰를 벗어날 지 여부를 결정할 수 있도록 경고를 표시하려고합니다. 나는 결과를 반환해야합니다UIAlertController의 결과를 동기화하는 방법은 무엇입니까?

extension CDFFormController: UINavigationBarDelegate { 

    public func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool { 
     if let entityViewController = self.topViewController as? MyEntityViewController { 
      if entityViewController.isEditing { 
       let semaphore = DispatchSemaphore(value: 0) 
       var result = false 
       let alert = UIAlertController(title: "Leave the view?", message: nil, preferredStyle: .alert) 
       alert.addAction(UIAlertAction(title: "leave", style: .default, handler: { _ in 
        result = true 
        semaphore.signal() 
       })) 
       alert.addAction(UIAlertAction(title: "cancel", style: .cancel, handler: { _ in 
        semaphore.signal() 
       })) 
       entityViewController.present(alert, animated: true, completion: nil) 

       semaphore.wait() 
       return result 
      } else { 
       return true 
      } 
     } else { 
      return true 
     } 

    } 

} 

, 그래서 나는 방법을 차단하는 DispatchSemaphore를 사용

이 내 코드입니다. 하지만 질문입니다 :이 방법은 메인 대기열에서 호출되며 그것을 차단하는 것은 UI 스레드를 차단한다는 것을 의미합니다.

또는 다른 해결책이 있습니까?

+0

'UIAlertController'의 .isBeingPresented가 귀하의 경우에 유용 할 수도 있습니다. 내 workaround 솔루션에서 사용한 : http://stackoverflow.com/a/43507005/5329717 다른 문제에 대한, 아마도 당신은 어떤 식 으로든 도움이 될 것입니다. –

+0

완료 핸들러를 대신 사용하십시오. – Sulthan

+0

이 델리게이트 메소드가 주 스레드 (UI 스레드)에서 호출되면 경고 컨트롤러 이벤트는 반환 될 때까지 표시 될 수 없습니다! –

답변

0

잘 될지 잘 모르겠다. 나는 이것을 시험하지 않았다.

extension CDFFormController: UINavigationBarDelegate { 

public func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool { 
    if let entityViewController = self.topViewController as? MyEntityViewController { 
     if entityViewController.isEditing { 
      let alert = UIAlertController(title: "Leave the view?", message: nil, preferredStyle: .alert) 
      alert.addAction(UIAlertAction(title: "leave", style: .default, handler: { _ in 
       let saveDelegate = navigationBar.delegate; 
       navigationBar.delegate = nil; 
       navigationBar.popItem(animated:YES); 
       navigationBar.delegate = saveDelegate; 
      })) 
      alert.addAction(UIAlertAction(title: "cancel", style: .cancel, handler:nil)) 
      entityViewController.present(alert, animated: true, completion: nil) 


      return false 
     } else { 
      return true 
     } 
    } else { 
     return true 
    } 

} 

} 

다른 방법으로는 RunLoop을 사용합니다. 그러나 나는 이것을 좋아하지 않는다.

extension CDFFormController: UINavigationBarDelegate { 

    public func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool { 
     if let entityViewController = self.topViewController as? MyEntityViewController { 
      if entityViewController.isEditing { 
       let state = 0 
       var result = false 
       let alert = UIAlertController(title: "Leave the view?", message: nil, preferredStyle: .alert) 
       alert.addAction(UIAlertAction(title: "leave", style: .default, handler: { _ in 
        state = 1 

       })) 
       alert.addAction(UIAlertAction(title: "cancel", style: .cancel, handler: { _ in 
        state = 2 
       })) 
       entityViewController.present(alert, animated: true, completion: nil) 

       while (state == 0) 
       { 
        RunLoop.current.run(until: Date(timeIntervalSinceNow: 0.5)) 
       } 
       return state == 1 
      } else { 
       return true 
      } 
     } else { 
      return true 
     } 

    } 

} 
+0

첫 번째 해결 방안은 *** 캐치되지 않은 예외로 인해 응용 프로그램을 종료합니다 'NSInternalInconsistencyException', 이유 : '컨트롤러가 관리하는 UINavigationBar에서 대리인을 수동으로 설정할 수 없습니다.', iOS에서 변경하지 못하게합니다. 대의원이지만, 그것은 좋은 지적입니다. 나는 같은 새로운 일을 할 수있는 플래그 속성을 사용할 수 있다고 생각한다. –

+0

두 번째도 좋아하지 않는다. 죽은 루프와 같은 사람은 아무도 없다. P –

+0

불행히도, 잡히지 않은 예외 'NSInternalInconsistencyException', 이유 : 'popNavigationItemAnimated를 호출 할 수 없습니다 : 컨트롤러가 관리하는 UINavigationBar에서 직접 호출 할 수 없습니다.' '. 하지만 UINavigationBar를 직접 관리하고 싶지는 않습니다. ( –

관련 문제