UIView
에서 그것 으로 갈 수있는 내장 된 방법 이 UIViewController
있습니까? 나는 당신이에서 얻을 수 알고 UIViewController
그에게 UIView
통한 [self view]
하지만 역 참조가 있는지 궁금 해서요?
답변
이것이 오랫동안 받아 들여진 대답이므로 더 나은 대답으로 수정해야한다고 생각합니다.
필요성에 대한 의견 :
- 뷰가 뷰 컨트롤러에 직접 액세스 할 필요는 없습니다.
- 대신 뷰는 뷰 컨트롤러와 독립적이어야하며 다른 컨텍스트에서 작동 할 수 있어야합니다.
- 뷰 컨트롤러와 인터페이싱하기 위해 뷰가 필요한 경우 권장되는 방법과 Cocoa에서 Apple이하는 일은 델리게이트 패턴을 사용하는 것입니다.
구현 방법의 예는 다음과 같습니다.
@protocol MyViewDelegate < NSObject >
- (void)viewActionHappened;
@end
@interface MyView : UIView
@property (nonatomic, assign) MyViewDelegate delegate;
@end
@interface MyViewController < MyViewDelegate >
@end
뷰는 델리게이트와 인터페이스하고 ( UITableView
예를 들어) 뷰 컨트롤러 또는 다른 클래스에서 구현되었는지는 중요하지 않습니다.
내 원래 답변은 다음과 같습니다. 권장하지 않습니다. 뷰 컨트롤러에 직접 액세스 할 수있는 나머지 답변도 없습니다.
기본 제공 방법이 없습니다. 당신이를 추가하여 주위를 얻을 수 있지만 IBOutlet
상의 UIView
와 인터페이스 빌더에서 이러한 연결이 권장되지 않습니다. 뷰는 뷰 컨트롤러에 대해 알 수 없습니다. 대신 @Phil M이 제안한대로 대리자로 사용할 프로토콜을 만들어야합니다.
답변
Brock이 게시 한 예제를 사용하여 UIViewController 대신 UIView 범주로 변경하고 하위 뷰가 부모 UIViewController를 찾을 수 있도록 재귀 적으로 만들었습니다.
@interface UIView (FindUIViewController)
- (UIViewController *) firstAvailableUIViewController;
- (id) traverseResponderChainForUIViewController;
@end
@implementation UIView (FindUIViewController)
- (UIViewController *) firstAvailableUIViewController {
// convenience function for casting and to "mask" the recursive function
return (UIViewController *)[self traverseResponderChainForUIViewController];
}
- (id) traverseResponderChainForUIViewController {
id nextResponder = [self nextResponder];
if ([nextResponder isKindOfClass:[UIViewController class]]) {
return nextResponder;
} else if ([nextResponder isKindOfClass:[UIView class]]) {
return [nextResponder traverseResponderChainForUIViewController];
} else {
return nil;
}
}
@end
이 코드를 사용하려면 새 클래스 파일 (내 이름은 “UIKit 카테고리”)에 추가하고 클래스 데이터를 제거하십시오. @interface를 헤더에 복사하고 @implementation을 .m 파일에 복사하십시오. 그런 다음 프로젝트에서 #import “UIKitCategories.h”를 가져 와서 UIView 코드 내에서 사용하십시오.
// from a UIView subclass... returns nil if UIViewController not available
UIViewController * myController = [self firstAvailableUIViewController];
답변
UIView
의 하위 클래스입니다 UIResponder
. 를 돌려주는 구현으로 UIResponder
메소드 -nextResponder
를 배치합니다 nil
. 다음과 같이 (어떤 이유로에 대신) UIView
문서화되어있는 것처럼이 메소드를 대체합니다 . 뷰 컨트롤러가없는 경우이 메서드는 수퍼 뷰를 반환합니다.UIResponder
UIView
-nextResponder
이것을 프로젝트에 추가하면 롤 준비가 된 것입니다.
@interface UIView (APIFix)
- (UIViewController *)viewController;
@end
@implementation UIView (APIFix)
- (UIViewController *)viewController {
if ([self.nextResponder isKindOfClass:UIViewController.class])
return (UIViewController *)self.nextResponder;
else
return nil;
}
@end
이제 UIView
뷰 컨트롤러를 반환하는 작업 방법이 있습니다.
답변
UIView에 범주를 추가하지 않고도 전체 응답자 체인을 통과하는보다 가벼운 접근 방식을 제안합니다.
@implementation MyUIViewSubclass
- (UIViewController *)viewController {
UIResponder *responder = self;
while (![responder isKindOfClass:[UIViewController class]]) {
responder = [responder nextResponder];
if (nil == responder) {
break;
}
}
return (UIViewController *)responder;
}
@end
답변
이미 주어진 여러 답변을 결합하여 구현과 함께 제공합니다.
@implementation UIView (AppNameAdditions)
- (UIViewController *)appName_viewController {
/// Finds the view's view controller.
// Take the view controller class object here and avoid sending the same message iteratively unnecessarily.
Class vcc = [UIViewController class];
// Traverse responder chain. Return first found view controller, which will be the view's view controller.
UIResponder *responder = self;
while ((responder = [responder nextResponder]))
if ([responder isKindOfClass: vcc])
return (UIViewController *)responder;
// If the view controller isn't found, return nil.
return nil;
}
@end
이 카테고리는 내 ARC 지원의 일부입니다 내가 만드는 모든 응용 프로그램에서 제공하는 정적 라이브러리의 . 여러 번 테스트를 받았으며 문제 나 누수를 찾지 못했습니다.
추신 : 관련보기가 귀하의 하위 클래스 인 경우처럼 카테고리를 사용할 필요가 없습니다. 후자의 경우 메소드를 서브 클래스에 넣으면됩니다.
답변
비록 이것이 pgb가 권장하는 IMHO에 의해 기술적으로 해결 될 수 있지만 , 이것은 디자인 결함입니다. 보기는 컨트롤러를 인식하지 않아도됩니다.
답변
나는 수정 드 내가 어떤보기 버튼을 통과 그것의 부모를 얻을 수 등의 레이블을 지정할 수 있도록 답을 UIViewController
. 여기 내 코드가 있습니다.
+(UIViewController *)viewController:(id)view {
UIResponder *responder = view;
while (![responder isKindOfClass:[UIViewController class]]) {
responder = [responder nextResponder];
if (nil == responder) {
break;
}
}
return (UIViewController *)responder;
}
스위프트 3 버전 편집
class func viewController(_ view: UIView) -> UIViewController {
var responder: UIResponder? = view
while !(responder is UIViewController) {
responder = responder?.next
if nil == responder {
break
}
}
return (responder as? UIViewController)!
}
편집 2 :-신속한 확장
extension UIView
{
//Get Parent View Controller from any view
func parentViewController() -> UIViewController {
var responder: UIResponder? = self
while !(responder is UIViewController) {
responder = responder?.next
if nil == responder {
break
}
}
return (responder as? UIViewController)!
}
}