একটি ভিউ দেওয়া হয়েছে, আমি কীভাবে এর ভিউকন্ট্রোলার পাব?


141

আমি একটি পয়েন্টার আছে UIView। আমি কীভাবে এর অ্যাক্সেস করব UIViewController? [self superview]অন্য UIView, কিন্তু না UIViewController, তাই না?


আমি মনে করি এই থ্রেডের উত্তর রয়েছে: আইফোন থেকে ইউআইভিউ থেকে ইউআইভিউকন্ট্রোলারে যান?
উশক্স

মূলত, আমার ভিউটি বরখাস্ত হওয়ায় আমি আমার ভিউকন্ট্রোলারের ভিউউইল অ্যাপয়ারকে কল করার চেষ্টা করছি। দৃশ্যটি নিজেই সেই ভিউটিকে খারিজ করা হচ্ছে যা একটি ন্যাপ সনাক্ত করে এবং কল করছে [স্ব-অপসারণফ্রোমস্পারভিউ]; ভিউকন্ট্রোলার ভিউইল অ্যাপয়ার / উইলডিস্পিয়ার / ডিড অ্যাপয়ার / ডিডিস্পিয়ার নিজেই কল করছে না।
মাহবাউদজ

আমি বোঝাতে চাইছিলাম যে আমার ভিউটি বরখাস্ত হওয়ায় আমি ভিউউইলডিস্পিয়ারকে কল করার চেষ্টা করছি।
মাহবুডজ

উত্তর:


42

হ্যাঁ, এটি superviewসেই দৃশ্য যা আপনার দৃষ্টিভঙ্গি ধারণ করে। আপনার দৃষ্টিভঙ্গিটি ঠিক কী এর ভিউ কন্ট্রোলার তা জানা উচিত নয়, কারণ এটি এমভিসি নীতিগুলি ভঙ্গ করে।

অন্যদিকে, কন্ট্রোলার জানে যে এটি কোন দৃষ্টির জন্য দায়ী ( self.view = myView) এবং সাধারণত, এই দৃষ্টিভঙ্গি নিয়ামককে পরিচালনা করার জন্য পদ্ধতি / ইভেন্টগুলির প্রতিনিধিত্ব করে।

সাধারণত আপনার দৃশ্যের দিকে নির্দেশকের পরিবর্তে আপনার নিয়ামকের কাছে আপনার পয়েন্টার থাকা উচিত যা ফলস্বরূপ কিছু নিয়ন্ত্রণকারী যুক্তি সম্পাদন করতে পারে বা তার দৃষ্টিতে কিছু সরবরাহ করতে পারে।


24
আমি নিশ্চিত না এটি এমভিসি নীতিমালা ভঙ্গ করবে কিনা। যে কোনও এক পর্যায়ে, একটি ভিউতে কেবলমাত্র একটি ভিউ নিয়ন্ত্রক থাকে। কোনও বার্তা এটিতে ফেরত দেওয়ার জন্য এটিতে সক্ষম হওয়া, একটি স্বয়ংক্রিয় বৈশিষ্ট্য হওয়া উচিত, যেখানে আপনাকে অর্জন করতে কাজ করতে হবে এমন নয় (ট্র্যাক রাখতে কোনও সম্পত্তি যুক্ত করে)। কেউ মতামত সম্পর্কে একই কথা বলতে পারে: আপনি কে সন্তানের তা জানা দরকার কেন? বা অন্য সহোদর দৃষ্টিভঙ্গি আছে কিনা। তবুও এই জিনিসগুলি পাওয়ার উপায় আছে।
মাহবাউদজ

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

9
মূল শব্দ: "সর্বাধিক"।
গ্লেন মেইনার্ড

278

এর UIResponderজন্য ডকুমেন্টেশন থেকে nextResponder:

ইউআইআরআইএসপোন্ডার শ্রেণি পূর্ববর্তী উত্তরদাতাকে স্বয়ংক্রিয়ভাবে সঞ্চয় বা সেট করে না, পরিবর্তে ডিফল্টরূপে শূন্য করে। পরবর্তী উত্তরদাতা সেট করতে সাবক্লাসগুলি অবশ্যই এই পদ্ধতিটিকে ওভাররাইড করতে হবে। ইউআইভিউউ এই পদ্ধতিটি পরিচালনা করে ইউআইভিউকন্ট্রোলার অবজেক্টটি যা এটি পরিচালনা করে (যদি এটি থাকে) বা এর তত্ত্বাবধান (যদি তা না হয়) ফিরে আসে ; ইউআইভিউকন্ট্রোলার তার দর্শনের তত্ত্বাবধানে ফিরে এসে পদ্ধতিটি প্রয়োগ করে; UIWindow অ্যাপ্লিকেশন অবজেক্টটি ফেরত দেয় এবং ইউআইএআইপ্লিকেশন শূন্য করে।

সুতরাং, যদি আপনি কোনও ভিউটি 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; \
})

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

ম্যাক্রো কাজ করে, আমি কেবল ব্যক্তিগতভাবে ম্যাক্রো সংস্করণটি ব্যবহার করি। আমি প্রচুর প্রকল্প শুরু করি এবং একটি শিরোলেখ থাকে আমি কেবলমাত্র এই ম্যাক্রো ইউটিলিটি ফাংশনগুলির একগুচ্ছ সাথে সর্বত্র ফেলে রাখি me আমার সময় সাশ্রয় করে। আপনি যদি ম্যাক্রোগুলিকে পছন্দ করেন না তবে আপনি এটিকে কোনও ফাংশনে রূপান্তর করতে পারেন তবে স্থির ফাংশনগুলি ক্লান্তিকর বলে মনে হয়, যেহেতু আপনি তখন এটি ব্যবহার করতে চান এমন প্রতিটি ফাইলে একটি করে রাখতে হবে। পরিবর্তে মনে হচ্ছে আপনি কোনও শিরোনামে ঘোষিত এবং একটি .m কোথাও সংজ্ঞায়িত একটি অ স্থির ফাংশন চান?
এমএক্সসিএল

কিছু প্রতিনিধি বা বিজ্ঞপ্তি এড়ানো ভাল লাগছে। ধন্যবাদ!
ফেরান মেলিনচ

আপনার এটির এক্সটেনশন করা উচিত UIResponder;)। খুব সম্পাদনকারী পোস্ট।
স্কটিব্ল্যাডেস

32

@ অ্যান্ড্রে এক লাইনে উত্তর ( সুইফট ৪.১-এ পরীক্ষিত ):

extension UIResponder {
    public var parentViewController: UIViewController? {
        return next as? UIViewController ?? next?.parentViewController
    }
}

ব্যবহার:

 let vc: UIViewController = view.parentViewController

parentViewControllerpublicএক্সটেনশনটি যদি একই ফাইলে থাকে তবে এটি UIViewসেট করতে পারেন fileprivate, সংজ্ঞায়িত করা যায় না এটি সংকলন করে কিন্তু এটি কার্যকর হয় না! 😐

এটা ঠিক কাজ করছে। আমি সাধারণ হেডার .xib ফাইলের অভ্যন্তরে ব্যাক বোতাম ক্রিয়াকলাপের জন্য এটি ব্যবহার করেছি।
ম্যাকডোনাল_11

23

শুধুমাত্র ডিবাগ উদ্দেশ্যে, আপনি ভিউগুলিতে _viewDelegateতাদের ভিউ কন্ট্রোলারগুলি পেতে কল করতে পারেন । এটি ব্যক্তিগত API, তাই অ্যাপ স্টোরের জন্য নিরাপদ নয়, তবে ডিবাগিংয়ের জন্য এটি দরকারী।

অন্যান্য দরকারী পদ্ধতি:

  • _viewControllerForAncestor- প্রথম নিয়ামক পান যা সুপারভিউ চেইনে একটি দৃশ্য পরিচালনা করে। (ধন্যবাদ n00neimp0rtant)
  • _rootAncestorViewController - পূর্বপুরুষের নিয়ামক পান যার ভিউটি উইন্ডোতে বর্তমানে সেট করা আছে।

ঠিক এই কারণেই আমি এই প্রশ্নে এসেছি। স্পষ্টতই, 'নেক্সট রিসপন্ডার' একই কাজ করে তবে আমি এই উত্তরটি উপলব্ধ করে তার প্রশংসা করি appreciate আমি বুঝেছি এবং এমভিসির মতোই, তবে ডিবাগিং অন্যরকম প্রাণী!
এমবিএম 29414

4
এটি প্রদর্শিত ভিউ নিয়ন্ত্রকের মূল দৃশ্যে কাজ করে, এর কোনও সংক্ষিপ্তসার নয় appears _viewControllerForAncestorততক্ষণ তত্ত্বাবধানগুলি পর্যবেক্ষণ করবে যতক্ষণ না এটি প্রথম দেখার জন্য একজন ভিউ কন্ট্রোলারের অন্তর্ভুক্ত।
n00neimp0rtant

ধন্যবাদ @ n00neimp0rtant! আমি এই উত্তরটিকে সমর্থন করছি যাতে লোকেরা আপনার মন্তব্য দেখে।
ইয়োল্ট

আরও পদ্ধতি সহ উত্তর আপডেট করুন।
লিও নাটান

1
ডিবাগ করার সময় এটি সহায়ক।
ইভানচিন

10

ইউআইভিউ কনকন্ট্রোলারের ইউআইভিউ থাকার বিষয়ে রেফারেন্স পেতে আপনি ইউআইআরআইএসপন্ডার (যা ইউআইভিউ এবং ইউআইভিউউকন্ট্রোলারের জন্য সুপার ক্লাস) বর্ধন করতে পারেন, যা প্রতিক্রিয়াশীল চেইনের মাধ্যমে যেতে পারে এবং এইভাবে ইউআইভিউউকন্ট্রোলারে পৌঁছাতে পারে (অন্যথায় শূন্যপদে ফিরে আসবে)।

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

4

সুইফট 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)
}

2

আপনি যদি কোডটির সাথে পরিচিত না হন এবং আপনি প্রদত্ত দর্শনে ভিউকন্ট্রোলার কোরস্পন্ডিং খুঁজে পেতে চান, তবে আপনি চেষ্টা করতে পারেন:

  1. ডিবাগে অ্যাপ চালান
  2. স্ক্রিনে নেভিগেট করুন
  3. পরিদর্শন পরিদর্শন শুরু করুন
  4. আপনি যে ভিউটি দেখতে চান তা ধরুন (বা একটি শিশু দর্শন আরও ভাল)
  5. ডান ফলকটি থেকে ঠিকানাটি পান (যেমন 0x7fe523bd3000)
  6. ডিবাগ কনসোলে কমান্ড লেখা শুরু করুন:
    po (ইউআইভিউ *) 0x7fe523bd3000
    po [(ইউআইভিউ *) 0x7fe523bd3000 পরবর্তী পুনরায় সরবরাহকারী]
    po [[(ইউআইভিউ *) 0x7fe523bd3000 পরের প্রতিবেদনকারী] পরবর্তী রেসপন্ডার]
    পো [[[(ইউআইভিউ *) 0x7fe523bd3000 পরবর্তী রেসপন্ডার] পরবর্তী রেসপন্ডার] পরবর্তী রেসপন্ডার]
    ...

বেশিরভাগ ক্ষেত্রে আপনি ইউআইভিউ পাবেন তবে সময়ে সময়ে ইউআইভিউউকন্ট্রোলার ভিত্তিক বর্গ থাকবে।


1

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


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

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

0

হায় আফসোস, আপনি যদি ভিউ সাবক্লাস না করেন এবং এটিকে কোনও দৃষ্টান্ত সম্পত্তি বা একই রকমের সাথে সরবরাহ না করেন যা দৃশ্যে যুক্ত হওয়ার সাথে সাথে তার ভিতরে ভিউ কন্ট্রোলার রেফারেন্স সঞ্চয় করে ...

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


0

কিছুটা দেরি হলেও এখানে একটি এক্সটেনশন যা আপনাকে ভিউকন্ট্রোলার সহ যে কোনও ধরণের প্রতিক্রিয়াশীল খুঁজে পেতে সক্ষম করে।

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

-1

আপনি যদি ব্রেক ব্রেকপয়েন্ট সেট করেন, তবে ভিউ হায়ারার্কি মুদ্রণের জন্য আপনি এটি ডিবাগারে পেস্ট করতে পারেন:

po [[UIWindow keyWindow] recursiveDescription]

আপনার গণ্ডগোলের কোথাও আপনার দেখার পিতামাতাকে খুঁজে পেতে সক্ষম হওয়া উচিত :)


recursiveDescriptionশুধুমাত্র দেখার শ্রেণিবিন্যাস ছাপায়, নিয়ন্ত্রণকারীদের নয় view
অ্যালান জেইনো

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