ইউআইভিউ থেকে ইউআইভিউকন্ট্রোলারটিতে যাবেন?


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এবং এটিকে ইন্টারফেস বিল্ডারে সংযুক্ত করে কাছাকাছি যেতে পারেন, এটির প্রস্তাব দেওয়া হয় না। ভিউটি নিয়ন্ত্রক সম্পর্কে জানতে হবে না। পরিবর্তে, আপনাকে @ ফিল এম এমের পরামর্শ অনুসারে কাজ করা উচিত এবং প্রতিনিধি হিসাবে ব্যবহার করার জন্য একটি প্রোটোকল তৈরি করা উচিত।


26
এটা খুব খারাপ পরামর্শ। আপনি একটি ভিউ থেকে একটি দৃশ্য নিয়ামক উল্লেখ করা উচিত নয়
ফিলিপ Leybaert

6
@ ম্যাটডিপিস্কোয়েল: হ্যাঁ, এটি খারাপ নকশা।
ফিলিপ লেবার্ট

23
@ ফিলিপ লেবার্ট আমি বাটন ক্লিক ইভেন্টের জন্য সেরা ডিজাইনের বিষয়ে আপনার ভাবনাগুলি জানার জন্য আগ্রহী, যা নিয়ামকের কোনও রেফারেন্স না রেখে নিয়ন্ত্রণকারীকে কিছু পদক্ষেপ নিতে হবে should ধন্যবাদ
জনাথন হর্সম্যান

3
@ ফিলিপেইলিবাবার্ট অ্যাপলের উদাহরণ প্রকল্পগুলিতে নির্দিষ্ট এপিআই বৈশিষ্ট্য ব্যবহারের প্রবণতা রয়েছে। অনেককে আমি এই বিষয়ের একটি সংক্ষিপ্ত প্রদর্শনের জন্য ভাল বা স্কেল্যাবল ডিজাইনের ত্যাগ করতে উল্লেখ করেছি। এটি উপলব্ধি করতে আমার অনেক সময় লেগেছে এবং এটি যখন বোধগম্য হয়, আমি এটি দুর্ভাগ্যজনক বলে মনে করি। আমি মনে করি অনেকগুলি বিকাশকারী এই নকশাকৃত প্রকল্পগুলিকে সেরা নকশা অনুশীলনের অ্যাপলের গাইড হিসাবে গ্রহণ করে, যা আমি নিশ্চিত যে তারা না।
বেনজোহান

11
"আপনার এটি করা উচিত নয়" সম্পর্কে এই সমস্ত বিএসগুলি কেবল এটিই। যদি কোনও ভিউ তার ভিউ কন্ট্রোলার সম্পর্কে জানতে চায় তবে তা প্রোগ্রামারের সিদ্ধান্ত নিতে হবে। সময়কাল।
ড্যানিয়েল কানান

203

ব্রোক পোস্ট করা উদাহরণ ব্যবহার করে, আমি এটিকে সংশোধন করেছি যাতে এটি ইউআইভিউ কনট্রোলারের পরিবর্তে ইউআইভিউয়ের একটি বিভাগ এবং এটিকে পুনরাবৃত্ত করে তোলে যাতে কোনও মতামত (আশাবাদী) প্যারেন্ট ইউআইভিউউকন্ট্রোলারকে খুঁজে পেতে পারে।

@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" রেখেছি) এবং শ্রেণীর ডেটা মুছে ফেলুন ... শিরোনামে @ ইন্টারফেসটি অনুলিপি করুন, এবং .m ফাইলটিতে @ ইমপ্লিমেন্টেশন copy তারপরে আপনার প্রকল্পে, "আমদানি করুন" UIKitCategories.h "এবং ইউআইভিউ কোডের মধ্যে ব্যবহার করুন:

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

47
এবং আপনি যখন ইউআইভিউউকে তার ইউআইভিউউ কনট্রোলার সম্পর্কে সচেতন হওয়ার অনুমতি দেওয়ার প্রয়োজন হচ্ছেন তখন আপনার যখন কাস্টম ইউআইভিউ সাবক্লাস থাকে যাতে কোনও মডেল ভিউ / ডায়ালগ চাপতে হয়।
ফিল এম

আশ্চর্যজনক, আমাকে একটি কাস্টম পপআপ প্রদর্শন করতে আমার ভিউকন্ট্রোলার অ্যাক্সেস করতে হয়েছিল যা একটি সাবউউ দ্বারা তৈরি করা হয়েছিল
অ্যারায়্যাক্ট

2
কোনও ইউআইভিউ-র কোনও মডেল ভিউকে ধাক্কা দেওয়ার জন্য কি এই খারাপ অভ্যাসটি নয়? আমি এখনই এটি করছি তবে আমি অনুভব করি এটি করা ঠিক জিনিস নয় ..
ভ্যান ডু ট্রান

6
ফিল, আপনার কাস্টম ভিউটিতে একটি প্রতিনিধি পদ্ধতি কল করা উচিত যা ভিউ কন্ট্রোলার শুনে এবং তারপরে সেখান থেকে ধাক্কা দেয়।
মালহাল

9
আমি কেবলমাত্র ভালবাসি যে কতগুলি এসও প্রশ্নের কাছে "জ্ঞানী মানুষ", একাডেমিক, গ্রহণযোগ্য উত্তর পেয়েছে মাত্র কয়েকটি পয়েন্ট এবং দ্বিতীয় উত্তর যা ব্যবহারিক, নোংরা এবং বিধি বিপরীতে, দশগুণ পয়েন্ট সহ :-)
হ্যারিসেলডন Jun78

114

UIViewএর একটি সাবক্লাস UIResponder। একটি বাস্তবায়ন যে UIResponderপদ্ধতিটি -nextResponderফিরে আসে তার সাথে পদ্ধতিটি রাখে nilUIViewএই পদ্ধতিটি ওভাররাইড করে যেমন নথিবদ্ধ হিসাবে UIResponder(এর পরিবর্তে কিছু কারণে UIView) এইভাবে: ভিউটিতে যদি একটি ভিউ কন্ট্রোলার থাকে তবে এটি দ্বারা ফিরে আসে -nextResponder। যদি কোনও ভিউ কন্ট্রোলার না থাকে তবে পদ্ধতিটি তদারকি করবে return

এটি আপনার প্রকল্পে যুক্ত করুন এবং আপনি রোল করতে প্রস্তুত।

@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

আমি ইউআইভিউতে কোনও বিভাগ যুক্ত না করে সম্পূর্ণ প্রতিক্রিয়াশীল চেইনটি অতিক্রম করার জন্য আরও হালকা ওজনের পদ্ধতির পরামর্শ দেব:

@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

যদিও এটি প্রযুক্তিগতভাবে পিজিবির পরামর্শ অনুসারে সমাধান করা যেতে পারে , আইএমএইচও, এটি একটি ডিজাইনের ত্রুটি। নিয়ামক সম্পর্কে দৃষ্টিভঙ্গি হওয়া উচিত নয়।


আমি ঠিক নিশ্চিত নই যে ভিউকন্ট্রোলারকে কীভাবে বলা যেতে পারে যে এর দৃশ্যের মধ্যে একটি চলেছে এবং তার ভিউএক্সএক্সএক্সএয়ার / ভিউ এক্সএক্সএক্সএক্সএক্সএইচপি পদ্ধতিগুলির মধ্যে একটির কল করতে হবে।
মাহবুডজ

2
এটি পর্যবেক্ষক নিদর্শন পিছনে ধারণা। পর্যবেক্ষণকারী (এই ক্ষেত্রে দেখুন) এর পর্যবেক্ষকদের সম্পর্কে সরাসরি সচেতন হওয়া উচিত নয়। পর্যবেক্ষকের কেবলমাত্র সেই কলব্যাকগুলি গ্রহণ করা উচিত যা তারা আগ্রহী
উশক্স

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];

তবে আপনাকে প্রথমে প্রথমে উইন্ডোর রুটভিউ কনট্রোলার সম্পত্তি সেট আপ করতে হবে। আপনি যখন প্রথম নিজের অ্যাপ্লিকেশন প্রতিনিধিতে নিয়ন্ত্রণকারী তৈরি করেন তখন এটি করুন:

-(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];
}

এটি আমার কাছে মনে হয় যেহেতু উইন্ডোটির "প্রধান" (উপ) ভিউ হিসাবে অ্যাপল ডক্স অনুসারে [[self navigationController] view]উইন্ডোর rootViewControllerবৈশিষ্ট্যটি সেট করতে হবে navigationControllerযা অবিলম্বে "প্রধান" দৃশ্যটি নিয়ন্ত্রণ করে controls
adubr

6

এই উত্তরগুলি উশক্স সহ প্রযুক্তিগতভাবে সঠিক হলেও, আমি মনে করি অনুমোদিত উপায়টি হল একটি নতুন প্রোটোকল বাস্তবায়ন করা বা কোনও বিদ্যমান ব্যবহারকারীর পুনরায় ব্যবহার। একটি প্রোটোকল পর্যবেক্ষককে পর্যবেক্ষক থেকে অন্তরক করে, যেমন তাদের মধ্যে কোনও মেল স্লট রাখার মতো। কার্যত, গ্যাব্রিয়েল এটি পুশভিউ কনট্রোলার পদ্ধতির অনুরোধের মাধ্যমে করে; এই ভিউটি "জানে" যে আপনার ন্যাভিগেশনকন্ট্রোলারকে বিনয়ের সাথে একটি দৃষ্টিভঙ্গি পোষণ করতে বলা উপযুক্ত প্রোটোকল, যেহেতু ভিউকন্ট্রোলার নেভিগেশনকন্ট্রোলার প্রোটোকলের সাথে সম্মতি রাখে। আপনি যখন নিজের প্রোটোকল তৈরি করতে পারেন, কেবল গ্যাব্রিয়েলের উদাহরণ ব্যবহার করে এবং ইউআইএনএভিগেশন কন্ট্রোলার প্রোটোকলটি পুনরায় ব্যবহার করা ঠিক আছে।


6

আমি এমন পরিস্থিতিতে পড়েছি যেখানে আমার একটি ছোট উপাদান রয়েছে যা আমি পুনঃব্যবহার করতে চাই এবং নিজেই পুনরায় ব্যবহারযোগ্য দৃশ্যে কিছু কোড যুক্ত করেছি (এটি সত্যিকার অর্থে একটি বোতাম খোলার চেয়ে বেশি কিছু নয় PopoverController)।

যদিও এটি আইপ্যাডে দুর্দান্ত কাজ করে ( UIPopoverControllerনিজেই উপস্থাপন করে, এর জন্য কোনও রেফারেন্সের প্রয়োজন নেই UIViewController), একই কোডটি কাজ করার অর্থ হঠাৎ আপনার presentViewControllerথেকে আপনার রেফারেন্স করা UIViewController। কিন্ডা বেমানান তাই না?

পূর্বে উল্লিখিত মত, এটি আপনার ইউআইভিউতে যুক্তিযুক্ত হওয়ার জন্য সেরা পন্থা নয়। তবে আলাদা কন্ট্রোলারে প্রয়োজনীয় কয়েকটি লাইন কোডের মোড়ক লাগানো সত্যিই অকেজো বলে মনে হয়েছে।

যে কোনও উপায়ে, এখানে একটি দ্রুত সমাধান রয়েছে, যা কোনও ইউআইভিউতে একটি নতুন সম্পত্তি যুক্ত করে:

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;

//.m

- (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: আমার কাছে একটি বস্তু রয়েছে যা চারপাশে মোড়ানো AVPlayer/ AVPlayerViewControllerএবং আমি একটি সাধারণ show(in view: UIView)পদ্ধতি সরবরাহ করতে চাই যা এম্বেড AVPlayerViewControllerহবে view। যে জন্য, আমি ব্যবহার করার দরকার view's UIViewController


3

এটি সরাসরি প্রশ্নের উত্তর দেয় না, বরং প্রশ্নের অভিপ্রায় সম্পর্কে ধারণা তৈরি করে।

আপনার যদি মতামত থাকে এবং সেই দৃশ্যে আপনাকে অন্য কোনও অবজেক্টে কোনও কল করতে হবে, যেমন ভিউ কন্ট্রোলার বলে, আপনি পরিবর্তে এনএসএনটিফিকেশন সেন্টার ব্যবহার করতে পারেন।

প্রথমে একটি শিরোনাম ফাইলে আপনার বিজ্ঞপ্তি স্ট্রিং তৈরি করুন

#define SLCopyStringNotification @"ShaoloCopyStringNotification"

আপনার দৃষ্টিতে কল পোস্টনিটিফিকেশন নাম:

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

তারপরে আপনার ভিউ কন্ট্রোলারে আপনি একটি পর্যবেক্ষক যুক্ত করুন। আমি ভিডিডলয়েডে এটি করি

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

এখন (একই দৃশ্যের নিয়ামকটিতেও) আপনার পদ্ধতিটি কপিস্ট্রিং বাস্তবায়িত করুন: উপরের @ নির্বাচিতে বর্ণিত।

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

আমি বলছি না এটি এটি করার সঠিক উপায়, এটি প্রথম প্রতিক্রিয়াশীল চেইন চালানোর চেয়ে পরিষ্কার মনে হয় seems আমি একটি ইউআইটিএবলভিউতে একটি ইউআইএমএনইউ কনট্রোলার বাস্তবায়ন করতে এবং ইভেন্টটি ইউআইভিউকন্ট্রোলারের কাছে ফেরত দেওয়ার জন্য এই কোডটি ব্যবহার করেছি যাতে আমি ডেটা দিয়ে কিছু করতে পারি।


3

এটি অবশ্যই একটি খারাপ ধারণা এবং একটি ভুল নকশা, তবে আমি নিশ্চিত যে আমরা সবাই @ ফিল্ম_এম প্রস্তাবিত সেরা উত্তরের একটি সুইফট সমাধান উপভোগ করতে পারি:

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)
}

যদি আপনার উদ্দেশ্য সাধারণ জিনিসগুলি করা, যেমন কোনও মডেল ডায়লগ বা ট্র্যাকিং ডেটা প্রদর্শন করা হয়, যা কোনও প্রোটোকলের ব্যবহারকে ন্যায়সঙ্গত করে না। আমি ব্যক্তিগতভাবে এই ফাংশনটি কোনও ইউটিলিটি অবজেক্টে সঞ্চয় করি, আপনি এটি ইউআরআইএসপেন্ডার প্রোটোকলটি প্রয়োগ করে এমন কোনও কিছু থেকে এটি ব্যবহার করতে পারেন:

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

@ ফিল_এম এর সমস্ত ক্রেডিট


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
    }
}

আমি এই উত্তর পছন্দ। আমি নিশ্চিত না যদিও এটি আরও দ্রুত if একাধিক-প্যারাডিজমগুলির মধ্যে-যা-হতে-বিবাহিত-হতে-বেছে নেওয়া ভাষাগুলি -গুলির-সিদ্ধান্ত-তা-সিদ্ধান্ত নিতে পারে না সুইফট-অন্যটি। এই ক্ষেত্রে, আপনার আরও কার্যকরী পদ্ধতির ( sequenceবিট) দুর্দান্ত প্রদর্শন রয়েছে। সুতরাং "সুইফটি" এর অর্থ যদি "আরও কার্যকর" হয় তবে আমি অনুমান করি এটি আরও তাত্ক্ষণিক।
ট্র্যাভিস গ্রিগস

2

সুইফ্ট 4 এর জন্য আপডেট হওয়া সংস্করণ: @ ফিল_এম এবং @ পল-স্ল্যামের জন্য ধন্যবাদ

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এখন কীওয়ার্ডের দরকার নেই 🤓

সমাধান 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]; যদি সেলফ (ইউআইভিউ) ভিউকন্ট্রোলারের দর্শনটির একটি সংক্ষিপ্তসার না হয়, আপনি যদি স্ব-স্তরক্রম (ইউআইভিউ) জানেন তবে আপনি এটিও ব্যবহার করতে পারেন: id nextResponder = [[self superview] nextResponder];...


0

আমার সমাধানটি সম্ভবত বোগাসের ধরণের হিসাবে বিবেচিত হবে তবে মায়োনিজের মতো আমারও একই অবস্থা ছিল (আমি একটি ইএজিএলভিউতে একটি অঙ্গভঙ্গির প্রতিক্রিয়াতে মতামত স্যুইচ করতে চেয়েছিলাম) এবং আমি এইভাবে ইএজিএল এর ভিউ কন্ট্রোলার পেয়েছি:

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

2
নিম্নরূপ আপনার কোড পুনর্লিখন করুন: EAGLViewController *vc = [(EAGLAppDelegate *)[UIApplication sharedApplication].delegate viewController];
জোনাথন স্টার্লিং

1
সমস্যাটি বিন্দু সিনট্যাক্সের সাথে নয়, তবে প্রকারের সাথে। অবজেক্টিভ সি তে একটি লিখিত চিহ্ন ঘোষণার জন্য ClassName *object- একটি নক্ষত্র দিয়ে।
Adubr

ওফ ... এটাই আসলে আমার কাছে ছিল তবে স্ট্যাকওভারফ্লো এইচটিএমএল উইজেট জিনিসটি দেখে মনে হচ্ছে যে এটি নক্ষত্রটি ইটালিকস বোঝায় ... আমি এটিকে একটি কোড ব্লকে পরিবর্তন করেছি, এখন এটি সঠিকভাবে প্রদর্শিত হয়। ধন্যবাদ!
gulchrider

0

আমি মনে করি এমন একটি মামলা আছে যখন পর্যবেক্ষকের পর্যবেক্ষককে অবহিত করা দরকার।

আমি একটি অনুরূপ সমস্যা দেখতে পাচ্ছি যেখানে কোনও ইউআইভিউকন্ট্রোলারের ইউআইভিউ একটি পরিস্থিতিতে সাড়া দিচ্ছে এবং প্রথমে পিছনে বোতামটি আড়াল করার জন্য তার প্যারেন্ট ভিউ কন্ট্রোলারকে বলা দরকার এবং তারপরে সমাপ্তির পরে অভিভাবক দর্শন নিয়ামককে বলুন যে এটি স্ট্যাক থেকে নিজেকে পপ করতে হবে।

আমি কোনও সাফল্য না নিয়ে প্রতিনিধিদের সাথে এটি চেষ্টা করে যাচ্ছি।

আমি বুঝতে পারি না কেন এটি খারাপ ধারণা হওয়া উচিত?


0

আর একটি সহজ উপায় হ'ল আপনার নিজস্ব ভিউ ক্লাস করা এবং ভিউ ক্লাসে ভিউ কন্ট্রোলারের একটি সম্পত্তি যুক্ত করা। সাধারণত ভিউ কন্ট্রোলার ভিউ তৈরি করে এবং সেখানেই নিয়ামক নিজেকে সম্পত্তিটিতে সেট করতে পারেন। মূলত এটি নিয়ামকের জন্য চারপাশে অনুসন্ধান করার পরিবর্তে (কিছুটা হ্যাকিংয়ের সাথে) নিয়ন্ত্রককে নিজের দৃষ্টিভঙ্গিতে সেট করার জন্য - এটি সহজ তবে বোধগম্য কারণ কারণ এটি নিয়ামক যা দৃশ্যের "নিয়ন্ত্রণ" করে।


0

আপনি যদি এটি অ্যাপ স্টোরটিতে আপলোড করতে যাচ্ছেন না, আপনি ইউআইভিউর একটি ব্যক্তিগত পদ্ধতিও ব্যবহার করতে পারেন।

@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

প্রদত্ত দৃশ্যের নিয়ামক পেতে, কেউ ইউআইএফআইআরআরসপন্ডার চেইন ব্যবহার করতে পারেন।

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

-1

যদি আপনার রুটভিউ কনট্রোলারটি ইউআইএনএভিগেশনভিউকন্ট্রোলার হয়, যা অ্যাপডেলিগেট শ্রেণিতে সেট আপ করা হয়েছিল, তবে

    + (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

কোন উপায় নেই.

আমি যা করি তা হল ইউআইভিউকন্ট্রোলার পয়েন্টারটি ইউআইভিউতে (বা একটি উপযুক্ত উত্তরাধিকার) পাস করা। আমি দুঃখিত আমি সমস্যার আইবি পদ্ধতির সাথে সহায়তা করতে পারি না কারণ আমি আইবিতে বিশ্বাস করি না।

প্রথম মন্তব্যকারীকে উত্তর দেওয়ার জন্য: কখনও কখনও আপনাকে জানতে হবে যে আপনাকে কে ডেকেছে কারণ এটি নির্ধারণ করে যে আপনি কী করতে পারেন। উদাহরণস্বরূপ, একটি ডাটাবেস সহ আপনার কেবল পঠিত অ্যাক্সেস থাকতে পারে বা পড়তে / লিখতে হবে ...


10
এর অর্থ কী - "আমি আইবিতে বিশ্বাস করি না"? আমি এটি চালু করেছি, এটি অবশ্যই বিদ্যমান।
মার্কসি

5
বিশেষ করে ইংরাজী ভাষার প্রতি আপনার মজাদার এবং বিমূর্ততার আরও ভাল উপলব্ধি দরকার। এর অর্থ আমি এটি পছন্দ করি না।
জন স্মিথ

4
আমি অ্যাভোকাডোস পছন্দ করি না। তবে আমি বাজি ধরেছি কাউকে গুয়াকামোল তৈরি করতে সহায়তা করতে পারি। এটি আইবিতে করা যেতে পারে, সুতরাং স্পষ্টতই আপনার "কোনও উপায় নেই" এর উত্তরটি ভুল। আপনি আইবি পছন্দ করেন বা না তা অপ্রাসঙ্গিক।
ভয়ঙ্কর বিড়াল
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.