뷰가 주어지면 뷰컨트롤러를 가져오려면 어떻게 해야 합니까?
에 대한 포인터가 있습니다.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 코어를 찾으려면 다음을 시도할 수 있습니다.
- 디버그에서 앱 실행
- 화면으로 이동
- 보기 검사기 시작
- 찾고자 하는 보기(또는 하위 보기)를 더 잘 가져옵니다.
- 오른쪽 창에서 주소를 가져옵니다(예: 0x7fe523bd3000).
- 디버그 콘솔에서 명령 쓰기를 시작합니다.
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
'UFO ET IT' 카테고리의 다른 글
WebClient.DownloadString()이 고유 문자가 포함된 문자열을 반환합니다. (0) | 2023.06.22 |
---|---|
CSV에서 JSON 루비 스크립트로? (0) | 2023.06.22 |
EPLUS C#에서 테이블 확장 (0) | 2023.06.22 |
단순 HTTP 서버에서 액세스 제어 사용 (0) | 2023.06.22 |
단일 숫자 벡터의 모든 요소 간 동일성 검정 (0) | 2023.06.22 |