UIView से UIViewController करें?


185

वहाँ है एक अंतर्निहित तरीका एक से प्राप्त करने के लिए UIViewअपने को UIViewController? मुझे पता है कि आप UIViewControllerइसके UIViewमाध्यम से प्राप्त कर सकते हैं [self view]लेकिन मैं सोच रहा था कि क्या कोई उल्टा संदर्भ है?

जवाबों:


46

चूंकि यह लंबे समय से स्वीकृत उत्तर है, मुझे लगता है कि मुझे बेहतर उत्तर के साथ इसे सुधारने की आवश्यकता है।

जरूरत पर कुछ टिप्पणियाँ:

  • आपके दृश्य को सीधे व्यू कंट्रोलर तक पहुंचने की आवश्यकता नहीं होनी चाहिए।
  • इसके बजाय दृश्य नियंत्रक से स्वतंत्र होना चाहिए, और विभिन्न संदर्भों में काम करने में सक्षम होना चाहिए।
  • क्या आपको व्यू कंट्रोलर के साथ एक तरह से इंटरफेस की सिफारिश की जानी चाहिए, अनुशंसित तरीका, और कोको के पार एप्पल क्या करता है, प्रतिनिधि पैटर्न का उपयोग करना है।

इसे कैसे लागू किया जाए, इसका एक उदाहरण:

@protocol MyViewDelegate < NSObject >

- (void)viewActionHappened;

@end

@interface MyView : UIView

@property (nonatomic, assign) MyViewDelegate delegate;

@end

@interface MyViewController < MyViewDelegate >

@end

दृश्य अपने प्रतिनिधि ( UITableViewउदाहरण के लिए, उदाहरण के लिए) के साथ इंटरफेस करता है और यह परवाह नहीं करता है कि क्या यह दृश्य नियंत्रक या किसी अन्य वर्ग में लागू होता है जिसे आप उपयोग कर रहे हैं।

मेरा मूल उत्तर इस प्रकार है: मैं इसकी अनुशंसा नहीं करता हूं, न ही बाकी उत्तर जहां व्यू कंट्रोलर की सीधी पहुंच है

इसे करने का कोई अंतर्निहित तरीका नहीं है। जबकि आप इंटरफ़ेस बिल्डर में इन IBOutletपर UIViewऔर जोड़कर इसके चारों ओर प्राप्त कर सकते हैं , यह अनुशंसित नहीं है। व्यू कंट्रोलर के बारे में जानकारी नहीं होनी चाहिए। इसके बजाय, आपको @Phil M सुझाव के रूप में करना चाहिए और प्रतिनिधि के रूप में उपयोग किए जाने के लिए एक प्रोटोकॉल बनाना चाहिए।


26
यह बहुत बुरी सलाह है। आपको किसी दृश्य नियंत्रक से दृश्य संदर्भ नहीं चाहिए
फिलिप लेबेर्ट

6
@MattDiPasquale: हां, यह खराब डिजाइन है।
फिलिप लेबेर्ट

23
@Phillipe Leybaert मैं बटन क्लिक करने की घटना के लिए सबसे अच्छे डिज़ाइन पर आपके विचार जानने के लिए उत्सुक हूं, जो नियंत्रक के संदर्भ को ध्यान में रखते हुए, नियंत्रक पर कुछ कार्रवाई करना चाहिए। धन्यवाद
जोनाथन Horsman

3
@PhilippeLeybaert Apple के उदाहरण प्रोजेक्ट्स विशेष एपीआई सुविधाओं के उपयोग को प्रदर्शित करते हैं। विषय के संक्षिप्त प्रदर्शन को प्रदान करने के लिए मैंने कई अच्छे या स्केलेबल डिज़ाइन का त्याग करने का उल्लेख किया है। मुझे इसे महसूस करने में काफी समय लगा और जब यह समझ में आता है, मुझे यह दुर्भाग्यपूर्ण लगता है। मुझे लगता है कि बहुत सारे डेवलपर्स इन व्यावहारिक परियोजनाओं को Apple के सर्वश्रेष्ठ डिजाइन अभ्यास के मार्गदर्शक के रूप में लेते हैं, जो कि मैं निश्चित हूं कि वे नहीं हैं।
बेन्जोन

11
यह सब के बारे में "आप यह नहीं करना चाहिए" बस इतना ही है। यदि कोई दृश्य इसके व्यू कंट्रोलर के बारे में जानना चाहता है, जो कि निर्णय लेने के लिए प्रोग्रामर पर निर्भर है। अवधि।
डैनियल कानन

203

ब्रॉक द्वारा पोस्ट किए गए उदाहरण का उपयोग करते हुए, मैंने इसे संशोधित किया ताकि यह 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

इस कोड का उपयोग करने के लिए, इसे एक नई कक्षा फ़ाइल (मुझे "UIKitCategories" नाम दिया गया है) में जोड़ें और वर्ग डेटा हटा दें ... शीर्ष लेख में @interface, और .m फ़ाइल में @ कार्यान्वयन लागू करें। फिर अपने प्रोजेक्ट में, #import "UIKitCategories.h" और UIView कोड का उपयोग करें:

// from a UIView subclass... returns nil if UIViewController not available
UIViewController * myController = [self firstAvailableUIViewController];

47
और एक कारण आपको UIView को इसके UIViewController के बारे में पता करने की अनुमति देने की आवश्यकता है जब आपके पास कस्टम UIView उपवर्ग होते हैं जिन्हें एक मोडल दृश्य / संवाद को पुश करने की आवश्यकता होती है।
फिल एम।

बहुत बढ़िया, मुझे एक कस्टम पॉपअप प्रदर्शित करने के लिए मेरे व्यूकंट्रोलर का उपयोग करना था जो कि एक
सबव्यू

2
क्या यह UIView के लिए एक बुरा दृष्टिकोण नहीं है? मैं अभी यह कर रहा हूं, लेकिन मुझे लगता है कि यह करना सही नहीं है ..
वैन डू ट्रान

6
फिल, आपके कस्टम दृश्य को एक प्रतिनिधि विधि को कॉल करना चाहिए जिसे दृश्य नियंत्रक सुनता है और फिर इसे वहां से धक्का देता है।
मल्हल

9
मैं सिर्फ इतना प्यार करता हूँ कि कितने SO प्रश्नों को एक "बुद्धिमान व्यक्ति" मिला है, कुछ ही बिंदुओं के साथ अकादमिक, स्वीकृत उत्तर और दूसरा उत्तर जो व्यावहारिक, गंदा और नियमों के विरुद्ध है, दस गुना अंकों के साथ :-)
hariseldon78

114

UIViewका एक उपवर्ग है UIResponder। एक कार्यान्वयन के साथ UIResponderविधि देता है -nextResponderजो वापस लौटता है nilUIViewइस पद्धति को ओवरराइड करता है, जैसा कि 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दृश्य नियंत्रक को वापस करने के लिए एक कार्य विधि है।


5
यह केवल तभी काम करेगा जब प्राप्तकर्ता UIViewऔर के बीच प्रत्युत्तर श्रृंखला में कुछ भी न हो UIViewController। पुनरावृत्ति की विशेषता फिल एम का जवाब जाने का रास्ता है।
ओलिवियर

33

मैं UIView पर एक श्रेणी जोड़ने के लिए बिना पूर्ण उत्तरदाता श्रृंखला को ट्रेस करने के लिए अधिक हल्के दृष्टिकोण का सुझाव दूंगा:

@implementation MyUIViewSubclass

- (UIViewController *)viewController {
    UIResponder *responder = self;
    while (![responder isKindOfClass:[UIViewController class]]) {
        responder = [responder nextResponder];
        if (nil == responder) {
            break;
        }
    }
    return (UIViewController *)responder;
}

@end

22

पहले से दिए गए कई उत्तरों को जोड़ते हुए, मैं इसे अपने कार्यान्वयन के साथ शिपिंग कर रहा हूं:

@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

श्रेणी मेरे एआरसी-सक्षम स्थिर पुस्तकालय का हिस्सा है जिसे मैं अपने द्वारा बनाए गए प्रत्येक एप्लिकेशन पर शिप करता हूं। यह कई बार परीक्षण किया गया है और मुझे कोई समस्या या लीक नहीं मिली।

पुनश्च: आपको किसी श्रेणी का उपयोग करने की आवश्यकता नहीं है जैसे मैंने किया था यदि संबंधित दृश्य आपका उपवर्ग है। बाद के मामले में, बस अपने उपवर्ग में विधि रखो और तुम जाने के लिए अच्छे हो।


1
यह सबसे अच्छा जवाब है। पुनरावृत्ति की आवश्यकता नहीं है, इस संस्करण को अच्छी तरह से अनुकूलित किया गया है
शून्य

12

भले ही यह तकनीकी रूप से pgb अनुशंसा के रूप में हल किया जा सकता है , IMHO, यह एक डिजाइन दोष है। व्यूअर को कंट्रोलर के बारे में पता होना चाहिए।


मुझे यकीन नहीं है कि व्यूकंट्रोलर को यह कैसे बताया जा सकता है कि उसका एक दृश्य दूर हो रहा है और उसे अपने एक व्यूएक्सएक्सएक्सऐपियर / व्यूएक्सएक्सएक्सडिसऐपियर तरीकों को कॉल करने की आवश्यकता है।
महबूदज़

2
यह ऑब्जर्वर पैटर्न के पीछे का विचार है। प्रेक्षित (इस मामले में देखें) को सीधे अपने पर्यवेक्षकों के बारे में पता नहीं होना चाहिए। प्रेक्षक को केवल उन कॉलबैक को प्राप्त करना चाहिए जिनकी वे रुचि रखते हैं।
Ushox

12

मैंने डी उत्तर को संशोधित किया है ताकि मैं इसे देखने के लिए कोई भी दृश्य, बटन, लेबल आदि पास कर सकूं 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)!
    }
}

7

मत भूलो कि आप विंडो के लिए रूट व्यू कंट्रोलर तक पहुंच प्राप्त कर सकते हैं जो कि दृश्य एक सबव्यू है। वहाँ से, यदि आप उदाहरण के लिए एक नेविगेशन व्यू कंट्रोलर का उपयोग कर रहे हैं और उस पर एक नया दृश्य पुश करना चाहते हैं:

    [[[[self window] rootViewController] navigationController] pushViewController:newController animated:YES];

हालाँकि आपको पहले ठीक से विंडो के rootViewController प्रॉपर्टी को सेट करना होगा। ऐसा तब करें जब आप पहली बार अपने ऐप के प्रतिनिधि में नियंत्रक बनाते हैं:

-(void) applicationDidFinishLaunching:(UIApplication *)application {
    window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    RootViewController *controller = [[YourRootViewController] alloc] init];
    [window setRootViewController: controller];
    navigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController];
    [controller release];
    [window addSubview:[[self navigationController] view]];
    [window makeKeyAndVisible];
}

मुझे ऐसा लगता है कि Apple डॉक्स के अनुसार चूंकि [[self navigationController] view]विंडो का "मुख्य" (सब) व्यू है, विंडो की rootViewControllerप्रॉपर्टी को सेट करना पड़ता है, navigationControllerजो "मेन" व्यू को तुरंत कंट्रोल करता है।
11'11

6

हालांकि ये उत्तर तकनीकी रूप से सही हैं, जिनमें उशॉक्स भी शामिल है, मुझे लगता है कि स्वीकृत तरीका एक नया प्रोटोकॉल लागू करना या किसी मौजूदा का फिर से उपयोग करना है। एक प्रोटोकॉल पर्यवेक्षक को उनके बीच एक मेल स्लॉट डालने की तरह, प्रेक्षित से निरीक्षण करता है। वास्तव में, यह वही है जो गेब्रियल पुश व्यूकंट्रोलर विधि के आह्वान के माध्यम से करता है; दृश्य "जानता है" यह उचित प्रोटोकॉल है कि विनम्रतापूर्वक अपने नेविगेशनकोंट्रोलर से एक दृश्य पुश करने के लिए कहें, क्योंकि व्यूकंट्रोलर नेविगेशनकंट्रोलर प्रोटोकॉल के अनुरूप है। जब आप अपना स्वयं का प्रोटोकॉल बना सकते हैं, तो केवल गेब्रियल के उदाहरण का उपयोग करके और यूनावीगेशन कॉन्ट्रोलर प्रोटोकॉल का फिर से उपयोग करना ठीक है।


6

मैं एक ऐसी स्थिति पर ठोकर खाई, जहां मेरे पास एक छोटा घटक है जिसका मैं पुन: उपयोग करना चाहता हूं, और पुन: प्रयोज्य दृश्य में कुछ कोड जोड़ा (यह वास्तव में एक बटन से अधिक नहीं है जो खुलता है PopoverController)।

जबकि यह iPad में ठीक काम करता है ( UIPopoverControllerखुद को प्रस्तुत करता है, इसके लिए कोई संदर्भ की आवश्यकता नहीं है UIViewController), काम करने के लिए समान कोड प्राप्त करने का मतलब है अचानक आपके अपने presentViewControllerसे संदर्भित करना UIViewController। Kinda असंगत अधिकार?

जैसा कि पहले उल्लेख किया गया है, यह आपके यूविवि में तर्क रखने का सबसे अच्छा तरीका नहीं है। लेकिन कोड की कुछ पंक्तियों को एक अलग नियंत्रक में लपेटना वास्तव में बेकार लगा।

किसी भी तरह से, यहाँ एक त्वरित समाधान है, जो किसी भी यूवाईवाईवाई में एक नई संपत्ति जोड़ता है:

extension UIView {

    var viewController: UIViewController? {

        var responder: UIResponder? = self

        while responder != nil {

            if let responder = responder as? UIViewController {
                return responder
            }
            responder = responder?.nextResponder()
        }
        return nil
    }
}

5

मुझे नहीं लगता कि यह पता लगाने के लिए "बुरा" विचार है कि कुछ मामलों के लिए कौन नियंत्रक है। इस नियंत्रक के संदर्भ को बचाने के लिए एक बुरा विचार क्या हो सकता है क्योंकि यह पर्यवेक्षकों के परिवर्तन के रूप में बदल सकता है। मेरे मामले में मेरे पास एक गेटर है जो उत्तरदाता श्रृंखला का पता लगाता है।

//.h

@property (nonatomic, readonly) UIViewController * viewController;

//।म

- (UIViewController *)viewController
{
    for (UIResponder * nextResponder = self.nextResponder;
         nextResponder;
         nextResponder = nextResponder.nextResponder)
    {
        if ([nextResponder isKindOfClass:[UIViewController class]])
            return (UIViewController *)nextResponder;
    }

    // Not found
    NSLog(@"%@ doesn't seem to have a viewController". self);
    return nil;
}

4

व्यूकंट्रोलर खोजने के लिए लूप करते समय सबसे सरल।

-(UIViewController*)viewController
{
    UIResponder *nextResponder =  self;

    do
    {
        nextResponder = [nextResponder nextResponder];

        if ([nextResponder isKindOfClass:[UIViewController class]])
            return (UIViewController*)nextResponder;

    } while (nextResponder != nil);

    return nil;
}

4

स्विफ्ट 4

(अन्य उत्तरों की तुलना में अधिक संक्षिप्त)

fileprivate extension UIView {

  var firstViewController: UIViewController? {
    let firstViewController = sequence(first: self, next: { $0.next }).first(where: { $0 is UIViewController })
    return firstViewController as? UIViewController
  }

}

मेरे उपयोग के मामले जिसके लिए मैं पहली बार देखने का उपयोग करने की जरूरत है UIViewController: मुझे लगता है कि wraps चारों ओर एक वस्तु है AVPlayer/ AVPlayerViewControllerऔर मैं एक सरल प्रदान करना चाहते हैं show(in view: UIView)विधि है कि एम्बेड कर देंगे AVPlayerViewControllerमें view। कि के लिए, मैं का उपयोग करने की जरूरत है view's UIViewController


3

यह सीधे सवाल का जवाब नहीं देता है, बल्कि सवाल के इरादे के बारे में एक धारणा बनाता है।

यदि आपके पास एक दृश्य है और उस दृश्य में आपको किसी अन्य ऑब्जेक्ट पर एक विधि को कॉल करने की आवश्यकता है, जैसे दृश्य नियंत्रक कहते हैं, तो आप इसके बजाय NSNotificationCenter का उपयोग कर सकते हैं।

सबसे पहले अपने नोटिफिकेशन स्ट्रिंग को हेडर फाइल में बनाएं

#define SLCopyStringNotification @"ShaoloCopyStringNotification"

आपके विचार में कॉल करें PostNotificationName:

- (IBAction) copyString:(id)sender
{
    [[NSNotificationCenter defaultCenter] postNotificationName:SLCopyStringNotification object:nil];
}

फिर अपने दृश्य नियंत्रक में आप एक पर्यवेक्षक जोड़ते हैं। मैं इसे देखने में करता हूँ

- (void)viewDidLoad
{
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(copyString:)
                                                 name:SLCopyStringNotification
                                               object:nil];
}

अब (समान दृश्य नियंत्रक में भी) अपने तरीके को कार्यान्वित करें copyString: जैसा कि ऊपर दिए गए @selector में दर्शाया गया है।

- (IBAction) copyString:(id)sender
{
    CalculatorResult* result = (CalculatorResult*)[[PercentCalculator sharedInstance].arrayTableDS objectAtIndex:([self.viewTableResults indexPathForSelectedRow].row)];
    UIPasteboard *gpBoard = [UIPasteboard generalPasteboard];
    [gpBoard setString:result.stringResult];
}

मैं यह नहीं कह रहा हूं कि ऐसा करने का यह सही तरीका है, यह सिर्फ पहली प्रतिक्रिया श्रृंखला को चलाने की तुलना में क्लीनर लगता है। मैंने इस कोड का उपयोग एक UIMableView पर एक UIMenuController को लागू करने और इवेंट को वापस UIViewController तक करने के लिए किया ताकि मैं डेटा के साथ कुछ कर सकूं।


3

यह निश्चित रूप से एक बुरा विचार और एक गलत डिजाइन है, लेकिन मुझे यकीन है कि हम सभी @P___ द्वारा प्रस्तावित सर्वश्रेष्ठ उत्तर के एक स्विफ्ट समाधान का आनंद ले सकते हैं:

static func firstAvailableUIViewController(fromResponder responder: UIResponder) -> UIViewController? {
    func traverseResponderChainForUIViewController(responder: UIResponder) -> UIViewController? {
        if let nextResponder = responder.nextResponder() {
            if let nextResp = nextResponder as? UIViewController {
                return nextResp
            } else {
                return traverseResponderChainForUIViewController(nextResponder)
            }
        }
        return nil
    }

    return traverseResponderChainForUIViewController(responder)
}

यदि आपका इरादा साधारण चीजें करना है, जैसे कि एक मॉडल संवाद या ट्रैकिंग डेटा, जो किसी प्रोटोकॉल के उपयोग को सही नहीं ठहराता है। मैं व्यक्तिगत रूप से इस फ़ंक्शन को एक उपयोगिता ऑब्जेक्ट में संग्रहीत करता हूं, आप इसका उपयोग किसी भी चीज़ से कर सकते हैं जो कि UIResponder प्रोटोकॉल को लागू करता है:

if let viewController = MyUtilityClass.firstAvailableUIViewController(self) {}

सारा श्रेय @Phil_M को


3

शायद मुझे यहां आने में देर हो गई। लेकिन इस स्थिति में मुझे श्रेणी (प्रदूषण) पसंद नहीं है। मैं इस तरह से प्यार करता हूँ:

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

3

स्विफ्टियर समाधान

extension UIView {
    var parentViewController: UIViewController? {
        for responder in sequence(first: self, next: { $0.next }) {
            if let viewController = responder as? UIViewController {
                return viewController
            }
        }
        return nil
    }
}

मुझे यह उत्तर पसंद है। मुझे यकीन नहीं है कि यह अधिक स्वाति है, हालांकि। स्विफ्ट अभी तक एक और है-नहीं-तय-जो-के-कई-प्रतिमानों-यह-चाहता है-से-विवाहित भाषाओं के लिए। इस मामले में, आपके पास अधिक कार्यात्मक दृष्टिकोण ( sequenceबिट) का अच्छा प्रदर्शन है । इसलिए यदि "स्विफ्टी" का अर्थ "अधिक कार्यात्मक" है, तो मुझे लगता है कि यह अधिक स्विफ्टी है।
ट्रैविस ग्रिग्स

2

स्विफ्ट 4 के लिए अपडेट किया गया संस्करण: @Phil_M और @ paul-slm के लिए धन्यवाद

static func firstAvailableUIViewController(fromResponder responder: UIResponder) -> UIViewController? {
    func traverseResponderChainForUIViewController(responder: UIResponder) -> UIViewController? {
        if let nextResponder = responder.next {
            if let nextResp = nextResponder as? UIViewController {
                return nextResp
            } else {
                return traverseResponderChainForUIViewController(responder: nextResponder)
            }
        }
        return nil
    }

    return traverseResponderChainForUIViewController(responder: responder)
}

2

स्विफ्ट 4 संस्करण

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
}

उदाहरण का उपयोग करें

 if let parent = self.view.parentViewController{

 }

2

स्विफ्ट 5.2 के रूप में दो समाधान :

  • क्रियात्मक पक्ष पर अधिक
  • returnअब कीवर्ड की कोई आवश्यकता नहीं है now

समाधान 1:

extension UIView {
    var parentViewController: UIViewController? {
        sequence(first: self) { $0.next }
            .first(where: { $0 is UIViewController })
            .flatMap { $0 as? UIViewController }
    }
}

समाधान 2:

extension UIView {
    var parentViewController: UIViewController? {
        sequence(first: self) { $0.next }
            .compactMap{ $0 as? UIViewController }
            .first
    }
}
  • इस समाधान को पहले प्रत्येक उत्तरदाता के माध्यम से पुनरावृत्ति की आवश्यकता होती है, इसलिए सबसे अधिक प्रदर्शन करने वाला नहीं हो सकता है।

1

फिल के जवाब के लिए:

लाइन में: id nextResponder = [self nextResponder]; यदि सेल्फ (UIView) ViewController के दृश्य का एक उप-भाग नहीं है, यदि आप स्वयं (UIView) के पदानुक्रम को जानते हैं, तो आप इसका भी उपयोग कर सकते हैं: id nextResponder = [[self superview] nextResponder];...


0

मेरे समाधान को संभवतः एक प्रकार का फर्जी माना जाएगा लेकिन मेरे पास भी ऐसी ही स्थिति थी जैसे मेयोनेज़ (मैं एक ईएजीएलव्यू में इशारे के जवाब में विचार स्विच करना चाहता था), और मुझे ईएजीएल का व्यू कंट्रोलर इस तरह मिला:

EAGLViewController *vc = ((EAGLAppDelegate*)[[UIApplication sharedApplication] delegate]).viewController;

2
इस प्रकार अपने कोड को फिर से लिखने करें: EAGLViewController *vc = [(EAGLAppDelegate *)[UIApplication sharedApplication].delegate viewController];
जोनाथन स्टर्लिंग

1
समस्या डॉट सिंटैक्स के साथ नहीं है, बल्कि प्रकारों के साथ है। ऑब्जेक्टिव C में आप लिखी गई वस्तु को घोषित करने के लिए ClassName *object- तारांकन के साथ।
adubr

ओह ... यह वास्तव में मेरे पास क्या था, लेकिन StackOverflow HTML विजेट बात यह है कि ऐसा लगता है कि तारांकन का मतलब इटैलिक था ... मैंने इसे एक कोड ब्लॉक में बदल दिया, अब यह सही ढंग से प्रदर्शित करता है। धन्यवाद!
gulchrider

0

मुझे लगता है कि एक ऐसा मामला है जब प्रेक्षक को पर्यवेक्षक को सूचित करने की आवश्यकता है।

मैं एक ऐसी ही समस्या देखता हूं जहां UIViewController में UIView एक स्थिति का जवाब दे रहा है और उसे बैक बटन छिपाने के लिए पहले अपने पैरेंट व्यू कंट्रोलर को बताना होगा और फिर पूरा होने पर पैरेंट व्यू कंट्रोलर को बताना होगा कि उसे खुद को स्टैक से पॉप करने की जरूरत है।

मैं कोशिश कर रहा हूं कि प्रतिनिधियों के साथ कोई सफलता न हो।

मुझे समझ नहीं आता कि यह एक बुरा विचार क्यों होना चाहिए?


0

एक और आसान तरीका यह है कि आप अपना व्यू क्लास रखें और व्यू क्लास में व्यू कंट्रोलर की प्रॉपर्टी जोड़ें। आमतौर पर व्यू कंट्रोलर व्यू बनाता है और यहीं कंट्रोलर प्रॉपर्टी को सेट कर सकता है। मूल रूप से यह नियंत्रक के लिए चारों ओर (हैकिंग के साथ) खोज करने के बजाय है, नियंत्रक को अपने आप को दृश्य पर सेट करने के लिए - यह सरल है लेकिन समझ में आता है क्योंकि यह नियंत्रक है जो दृश्य को "नियंत्रित" करता है।


0

यदि आप इसे ऐप स्टोर पर अपलोड नहीं करने जा रहे हैं, तो आप UIView की एक निजी पद्धति का भी उपयोग कर सकते हैं।

@interface UIView(Private)
- (UIViewController *)_viewControllerForAncestor;
@end

// Later in the code
UIViewController *vc = [myView _viewControllerForAncestor];

0
var parentViewController: UIViewController? {
    let s = sequence(first: self) { $0.next }
    return s.compactMap { $0 as? UIViewController }.first
}

हालाँकि यह कोड प्रश्न का उत्तर दे सकता है, लेकिन एक अच्छे उत्तर में यह भी बताया जाना चाहिए कि कोड क्या करता है और यह कैसे समस्या का हल करता है।
बीडीएल

0

किसी दिए गए दृश्य का नियंत्रक प्राप्त करने के लिए, व्यक्ति UIFirstResponder श्रृंखला का उपयोग कर सकता है।

customView.target(forAction: Selector("viewDidLoad"), withSender: nil)

-1

यदि आपका rootViewController UINavigationViewController है, जो कि AppDelegate वर्ग में स्थापित किया गया था, तो

    + (UIViewController *) getNearestViewController:(Class) c {
NSArray *arrVc = [[[[UIApplication sharedApplication] keyWindow] rootViewController] childViewControllers];

for (UIViewController *v in arrVc)
{
    if ([v isKindOfClass:c])
    {
        return v;
    }
}

return nil;}

जहां सी आवश्यक दृश्य नियंत्रकों वर्ग।

उपयोग:

     RequiredViewController* rvc = [Utilities getNearestViewController:[RequiredViewController class]];

-5

अब कोई रास्ता नहीं है।

मैं क्या करता हूं UIViewController पॉइंटर को UIView (या एक उपयुक्त उत्तराधिकार) पास करता है। मुझे खेद है कि मैं समस्या के लिए आईबी दृष्टिकोण के साथ मदद नहीं कर सकता क्योंकि मुझे आईबी पर विश्वास नहीं है।

पहले टिप्पणीकार का जवाब देने के लिए: कभी-कभी आपको यह जानने की जरूरत है कि आपको किसने बुलाया क्योंकि यह निर्धारित करता है कि आप क्या कर सकते हैं। उदाहरण के लिए एक डेटाबेस के साथ आप केवल पढ़ सकते हैं या पढ़ सकते हैं / लिख सकते हैं ...


10
इसका क्या मतलब है - "मैं आईबी पर विश्वास नहीं करता"? मैंने इसे लॉन्च किया है, यह निश्चित रूप से मौजूद है।
marcc

5
आपको विशेष रूप से अंग्रेजी भाषा के संबंध में मजेदार और अमूर्तता का एक बेहतर समझ चाहिए। इसका मतलब है कि मुझे यह पसंद नहीं है।
जॉन स्मिथ

4
मुझे एवोकाडोस पसंद नहीं है। लेकिन मैं शर्त लगाता हूं कि मैं किसी को गुआमकोल बनाने में मदद कर सकता हूं। यह आईबी में किया जा सकता है, इसलिए स्पष्ट रूप से "कोई रास्ता नहीं है" का आपका उत्तर गलत है। चाहे आप IB को पसंद करते हों या नहीं, अप्रासंगिक है।
फेलोनेस कैट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.