मैं एक के लिए एक सूचक है UIView
। मैं इसकी पहुँच कैसे करूँ UIViewController
? [self superview]
एक और है UIView
, लेकिन UIViewController
ठीक नहीं है?
मैं एक के लिए एक सूचक है UIView
। मैं इसकी पहुँच कैसे करूँ UIViewController
? [self superview]
एक और है UIView
, लेकिन UIViewController
ठीक नहीं है?
जवाबों:
हां, वह superview
दृश्य है जिसमें आपका दृश्य शामिल है। आपके विचार को यह नहीं पता होना चाहिए कि वास्तव में इसका दृश्य नियंत्रक क्या है, क्योंकि यह MVC सिद्धांतों को तोड़ देगा।
दूसरी ओर, नियंत्रक जानता है कि यह किस दृश्य के लिए जिम्मेदार है ( self.view = myView
), और आमतौर पर, यह दृश्य नियंत्रक से निपटने के लिए तरीकों / घटनाओं को दर्शाता है।
आमतौर पर, आपके दृष्टिकोण के लिए एक संकेतक के बजाय, आपके पास अपने नियंत्रक के लिए एक संकेतक होना चाहिए, जो बदले में या तो कुछ नियंत्रित तर्क को निष्पादित कर सकता है, या इसके दृश्य के लिए कुछ पास कर सकता है।
के लिए UIResponder
प्रलेखन से nextResponder
:
UIResponder वर्ग डिफ़ॉल्ट रूप से nil लौटने के बजाय, अगले प्रत्युत्तर को स्वचालित रूप से संग्रहीत या सेट नहीं करता है। अगले उत्तरदाता को सेट करने के लिए उपवर्गों को इस विधि को ओवरराइड करना चाहिए। UIView इस विधि को लागू करता है UIViewController वस्तु को वापस करके जो इसे प्रबंधित करता है (यदि इसमें एक है) या इसका पर्यवेक्षण (यदि यह नहीं है) ; UIViewController अपने दृष्टिकोण के पर्यवेक्षण को वापस करके विधि को लागू करता है; UIWindow एप्लिकेशन ऑब्जेक्ट लौटाता है, और UIApplication nil देता है।
इसलिए, यदि आप किसी दृश्य को nextResponder
तब तक पुनरावृत्ति करते हैं, जब तक वह टाइप का न हो UIViewController
, तो आपके पास किसी भी दृश्य का जनक दृश्य नियंत्रक है।
ध्यान दें कि इसमें अभी भी पैरेंट व्यू कंट्रोलर नहीं हो सकता है। लेकिन केवल अगर दृश्य एक व्यू कॉन्ट्रॉलर के दृश्य पदानुक्रम का हिस्सा नहीं है।
स्विफ्ट 3 और स्विफ्ट 4.1 एक्सटेंशन:
extension UIView {
var parentViewController: UIViewController? {
var parentResponder: UIResponder? = self
while parentResponder != nil {
parentResponder = parentResponder?.next
if let viewController = parentResponder as? UIViewController {
return viewController
}
}
return nil
}
}
स्विफ्ट 2 एक्सटेंशन:
extension UIView {
var parentViewController: UIViewController? {
var parentResponder: UIResponder? = self
while parentResponder != nil {
parentResponder = parentResponder!.nextResponder()
if let viewController = parentResponder as? UIViewController {
return viewController
}
}
return nil
}
}
उद्देश्य-सी श्रेणी:
@interface UIView (mxcl)
- (UIViewController *)parentViewController;
@end
@implementation UIView (mxcl)
- (UIViewController *)parentViewController {
UIResponder *responder = self;
while ([responder isKindOfClass:[UIView class]])
responder = [responder nextResponder];
return (UIViewController *)responder;
}
@end
यह मैक्रो श्रेणी प्रदूषण से बचा जाता है:
#define UIViewParentController(__view) ({ \
UIResponder *__responder = __view; \
while ([__responder isKindOfClass:[UIView class]]) \
__responder = [__responder nextResponder]; \
(UIViewController *)__responder; \
})
UIResponder
;) बहुत ही एडिटिंग पोस्ट।
एक लाइन में @andrey उत्तर ( स्विफ्ट 4.1 में परीक्षण किया गया ):
extension UIResponder {
public var parentViewController: UIViewController? {
return next as? UIViewController ?? next?.parentViewController
}
}
उपयोग:
let vc: UIViewController = view.parentViewController
parentViewController
परिभाषित नहीं किया जा सकता है public
यदि एक्सटेंशन आपके साथ एक ही फ़ाइल में है जिसे UIView
आप इसे सेट कर सकते हैं fileprivate
, यह संकलन करता है लेकिन यह काम नहीं करता है! 😐
केवल डिबग उद्देश्यों के लिए, आप _viewDelegate
उनके दृश्य नियंत्रकों को प्राप्त करने के लिए विचारों पर कॉल कर सकते हैं । यह निजी एपीआई है, इसलिए ऐप स्टोर के लिए सुरक्षित नहीं है, लेकिन डिबगिंग के लिए यह उपयोगी है।
अन्य उपयोगी तरीके:
_viewControllerForAncestor
- पहला कंट्रोलर मिलता है जो सुपरवाइज चेन में एक व्यू को मैनेज करता है। (साभार n00neimp0rtant)_rootAncestorViewController
- पूर्वज नियंत्रक प्राप्त करें जिसका दृश्य पदानुक्रम वर्तमान में विंडो में सेट किया गया है।_viewControllerForAncestor
जब तक कि यह पहले एक व्यू कंट्रोलर से संबंधित न हो जाए, तब तक पर्यवेक्षणियों को आगे बढ़ाएगा।
UIViewController का संदर्भ लेने के लिए UIView होने के कारण, आप UIResponder (जो UIView और UIViewController के लिए सुपर क्लास है) का विस्तार कर सकते हैं, जो उत्तरदाता श्रृंखला के माध्यम से ऊपर जाने की अनुमति देता है और इस प्रकार UIViewController (अन्यथा शून्य)।
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
स्विफ्ट 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 को दिए गए दृश्य के अनुरूप देखना चाहते हैं, तो आप कोशिश कर सकते हैं:
po (UIView *) 0x7fe523bd3000 पो [[(UIView *) 0x7fe523bd3000 अगला छापेदार] पो [[(उविव्यू *) ०xb फै ५२३ डब्लू ३००० नेक्स्टपोन्डर] नेक्स्टपोन्डर] पो [[[(यूआईवाईईवाई *) ० एक्स 23 एफ ५२३ डब्लू ३००० नेक्स्टपोन्डर] नेक्स्टपोन्डर] नेक्स्टपोन्डर] ...
ज्यादातर मामलों में आपको UIView मिलेगा, लेकिन समय-समय पर UIViewController आधारित कक्षा होगी।
मुझे लगता है कि आप नल को व्यू कंट्रोलर को प्रोपेगेट कर सकते हैं और इसे हैंडल कर सकते हैं। यह अधिक स्वीकार्य दृष्टिकोण है। किसी व्यू कंट्रोलर को उसके व्यू से एक्सेस करने के लिए, आपको व्यू कंट्रोलर के संदर्भ को बनाए रखना चाहिए, क्योंकि कोई दूसरा तरीका नहीं है। इस थ्रेड को देखें, यह मदद कर सकता है: व्यू कंट्रोलर को किसी व्यू से एक्सेस करना
स्विफ्ट 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
}
}
काश, यह असंभव है जब तक आप दृश्य को उप-वर्ग नहीं करते हैं और इसे एक उदाहरण संपत्ति या एक जैसे प्रदान करते हैं जो दृश्य में दृश्य में जोड़े जाने पर दृश्य नियंत्रक संदर्भ को इसके अंदर संग्रहीत करता है ...
ज्यादातर मामलों में - इस पोस्ट की मूल समस्या के आस-पास काम करना बहुत आसान है क्योंकि अधिकांश व्यू कंट्रोलर प्रोग्रामर के लिए अच्छी तरह से ज्ञात संस्थाएँ हैं, जो व्यूकंट्रोलर के व्यू में किसी भी सबव्यू को जोड़ने के लिए जिम्मेदार थे;; कभी भी उस संपत्ति को जोड़ने की जहमत नहीं उठाई।
थोड़ा देर से, लेकिन यहां एक ऐसा विस्तार है जो आपको व्यूकंट्रोलर सहित किसी भी प्रकार का उत्तर खोजने में सक्षम बनाता है।
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]
आपको उस झंझट में कहीं न कहीं अपने विचार के माता-पिता को खोजने में सक्षम होना चाहिए :)
recursiveDescription
केवल दृश्य पदानुक्रम को प्रिंट करता है, न कि नियंत्रकों को देखता है।