UFO ET IT

뷰가 주어지면 뷰컨트롤러를 가져오려면 어떻게 해야 합니까?

ufoet 2023. 6. 22. 23:11
반응형

뷰가 주어지면 뷰컨트롤러를 가져오려면 어떻게 해야 합니까?

에 대한 포인터가 있습니다.UIView액스방에 접속하려면 ?UIViewController?[self superview]는 또 다른 또른입니다.UIView그러나 그것은 아닙니다.UIViewController 렇죠그?

UIResponder에대문서에 대한 .nextResponder:

UIResponder 클래스는 자동으로 다음 응답기를 저장하거나 설정하지 않으며, 대신 기본적으로 0을 반환합니다.다음 응답측을 설정하려면 하위 클래스가 이 메서드를 재정의해야 합니다.UIView는 관리하는 UIViewController 개체(있는 경우) 또는 해당 수퍼뷰(없는 경우)를 반환하여 메서드를 구현하고, UIViewController는 뷰의 수퍼뷰를 반환하여 메서드를 구현하며, UIViewController는 응용 프로그램 개체를 반환하고, UIViewController는 0을 반환합니다.

보기를 반복하면 다음과 같이 됩니다.nextResponder그것이 활자가 될 때까지.UIViewController그러면 모든 뷰의 상위 뷰컨트롤러가 나타납니다.

여전히 상위 보기 컨트롤러가 없을 수 있습니다.그러나 뷰에 컨트롤러 뷰의 뷰 계층 구조가 없는 경우에만 해당됩니다.

Swift 3 및 Swift 4.1 확장:

extension UIView {
    var parentViewController: UIViewController? {
        // Starts from next (As we know self is not a UIViewController).
        var parentResponder: UIResponder? = self.next
        while parentResponder != nil {
            if let viewController = parentResponder as? UIViewController {
                return viewController
            }
            parentResponder = parentResponder?.next
        }
        return nil
    }
}

Swift 2 확장:

extension UIView {
    var parentViewController: UIViewController? {
        var parentResponder: UIResponder? = self.nextResponder()
        while parentResponder != nil {
            if let viewController = parentResponder as? UIViewController {
                return viewController
            }
            parentResponder = parentResponder!.nextResponder()
        }
        return nil
    }
}

목표-C 범주:

@interface UIView (mxcl)
- (UIViewController *)parentViewController;
@end

@implementation UIView (mxcl)
- (UIViewController *)parentViewController {
    UIResponder *responder = [self nextResponder];
    while (responder != nil) {
        if ([responder isKindOfClass:[UIViewController class]]) {
            return (UIViewController *)responder;
        }
        responder = [responder nextResponder];
    }
    return nil;
}
@end

이 매크로는 범주 오염을 방지합니다.

#define UIViewParentController(__view) ({ \
    UIResponder *__responder = __view; \
    while ([__responder isKindOfClass:[UIView class]]) \
        __responder = [__responder nextResponder]; \
    (UIViewController *)__responder; \
})

@Andrey는 한 줄로 답합니다(Swift 4.1에서 테스트됨).

extension UIResponder {
    public var parentViewController: UIViewController? {
        return next as? UIViewController ?? next?.parentViewController
    }
}

용도:

 let vc: UIViewController = view.parentViewController

네, 그superview사용자의 보기를 포함하는 보기입니다.MVC 원칙을 위반할 수 있기 때문에 뷰 컨트롤러가 정확히 어떤 것인지 알 수 없습니다.

에 컨트롤러는 를 담당하는지 있습니다(컨트롤러는 어떤 뷰를담당하는지 알고 있습니다self.view = myView및이 및 일반적으로 이 보기는 처리 방법/방법을 컨트롤러에 위임합니다.

일반적으로 뷰에 대한 포인터 대신 컨트롤러에 대한 포인터가 있어야 합니다. 컨트롤러는 제어 논리를 실행하거나 뷰에 무언가를 전달할 수 있습니다.

디그목전수할있다니습화만버를 할 수 ._viewDelegate보기 컨트롤러를 가져올 수 있습니다.이것은 개인 API이므로 앱스토어에는 안전하지 않지만 디버깅에는 유용합니다.

기타 유용한 방법:

  • _viewControllerForAncestor슈퍼뷰 체인에서 뷰를 관리하는 첫 번째 컨트롤러를 가져옵니다.(감사합니다 n00neimp0rtant)
  • _rootAncestorViewController현재 창에 뷰 계층이 설정된 상위 컨트롤러를 가져옵니다.

UIView가 있는 UIViewController에 대한 참조를 얻으려면 UIResponder(UIView 및 UIViewController의 슈퍼 클래스)를 확장하여 응답기 체인을 통해 올라가 UIViewController에 도달할 수 있습니다(그렇지 않으면 0으로 반환됨).

extension UIResponder {
    func getParentViewController() -> UIViewController? {
        if self.nextResponder() is UIViewController {
            return self.nextResponder() as? UIViewController
        } else {
            if self.nextResponder() != nil {
                return (self.nextResponder()!).getParentViewController()
            }
            else {return nil}
        }
    }
}

//Swift 3
extension UIResponder {
    func getParentViewController() -> UIViewController? {
        if self.next is UIViewController {
            return self.next as? UIViewController
        } else {
            if self.next != nil {
                return (self.next!).getParentViewController()
            }
            else {return nil}
        }
    }
}

let vc = UIViewController()
let view = UIView()
vc.view.addSubview(view)
view.getParentViewController() //provide reference to vc

Swift 3의 빠르고 일반적인 방법:

extension UIResponder {
    func parentController<T: UIViewController>(of type: T.Type) -> T? {
        guard let next = self.next else {
            return nil
        }
        return (next as? T) ?? next.parentController(of: T.self)
    }
}

//Use:
class MyView: UIView {
    ...
    let parentController = self.parentController(of: MyViewController.self)
}

코드에 익숙하지 않은 경우 지정된 보기에 해당하는 ViewController 코어를 찾으려면 다음을 시도할 수 있습니다.

  1. 디버그에서 앱 실행
  2. 화면으로 이동
  3. 보기 검사기 시작
  4. 찾고자 하는 보기(또는 하위 보기)를 더 잘 가져옵니다.
  5. 오른쪽 창에서 주소를 가져옵니다(예: 0x7fe523bd3000).
  6. 디버그 콘솔에서 명령 쓰기를 시작합니다.
po (UIView *)0x7fe523bd3000po [(UIView *)0x7fe523bd3000 nextResponder]po [(UIView *)0x7fe523bd3000 nextResponder] nextResponder]po[(UIView *)0x7fe523bd3000 nextResponder] nextResponder] nextResponder]...

대부분의 경우 UIView가 제공되지만, 때때로 UIViewController 기반 클래스가 제공됩니다.

탭을 뷰 컨트롤러에 전파하여 처리하도록 할 수 있다고 생각합니다.이 방법이 더 허용 가능합니다.뷰에서 뷰 컨트롤러에 액세스하는 경우 다른 방법이 없으므로 뷰 컨트롤러에 대한 참조를 유지해야 합니다.이 스레드를 참조하십시오. 도움이 될 수 있습니다. 보기에서 보기 컨트롤러 액세스

Swift 3.0에 대한 더 많은 유형의 안전 코드

extension UIResponder {
    func owningViewController() -> UIViewController? {
        var nextResponser = self
        while let next = nextResponser.next {
            nextResponser = next
            if let vc = nextResponser as? UIViewController {
                return vc
            }
        }
        return nil
    }
}

보기를 하위 분류하고 보기가 씬(scene)에 추가되면 뷰 컨트롤러 참조를 내부에 저장하는 인스턴스(instance) 특성 등을 제공하지 않는 한 이 작업은 불가능합니다.

대부분의 경우 - 대부분의 뷰 컨트롤러는 뷰 컨트롤러의 뷰에 하위 뷰를 추가하는 것을 담당했던 프로그래머에게 잘 알려진 엔티티이기 때문에 이 게시물의 원래 문제를 해결하는 것이 매우 쉽습니다;-). 그래서 애플은 결코 그 속성을 추가하려고 하지 않았다고 생각합니다.

조금 늦었지만 ViewController를 포함한 모든 유형의 응답자를 찾을 수 있는 확장 기능이 있습니다.

extension NSObject{
func findNext(type: AnyClass) -> Any{
    var resp = self as! UIResponder

    while !resp.isKind(of: type.self) && resp.next != nil
    {
        resp = resp.next!
    }

    return resp
  }                       
}

중단점을 설정한 경우 이를 디버거에 붙여넣어 보기 계층을 인쇄할 수 있습니다.

po [[UIWindow keyWindow] recursiveDescription]

당신은 그 난장판 어딘가에서 당신의 견해의 부모를 찾을 수 있어야 합니다 :)

언급URL : https://stackoverflow.com/questions/1372977/given-a-view-how-do-i-get-its-viewcontroller

반응형