2009-03-14 16 views
26

मेरे पास एक कस्टम UIViewController और कस्टम UIView है। मैं MyCustomUIView को वापस करने के लिए viewcontroller.view संपत्ति को ओवरराइड करना चाहता हूं।मैं UIViewController में "दृश्य" संपत्ति को ओवरराइड कैसे करूं?

अभी मेरे पास है:

@interface MyViewController : UIViewController {  
    IBOutlet MyView* view; 
} 

@property (nonatomic, retain) IBOutlet MyView* view; 

यह संकलित लेकिन मैं एक चेतावनी मिलती है: संपत्ति 'दृश्य' प्रकार सुपर क्लास 'UIViewController' संपत्ति प्रकार से मेल नहीं खाता।

मैं इस चेतावनी को कैसे कम कर सकता हूं?

+2

मुझे लगता है कि अगर आप का उपयोग करना चाहिए '@ dynamic'। कृपया [इस सवाल] को पढ़ें (http://stackoverflow.com/questions/1160498/synthesize-vs-dynamic-what-are-the-differences), उत्तर वास्तव में मेरे लिए उपयोगी थे :) – Ondrej

+3

बहुत अच्छा लेख है कहा जाता है [UIViewController की दृश्य संपत्ति ओवरराइडिंग, सही हो गया] (http://travisjeffery.com/b/2012/12/overriding-uiviewcontrollers-view-property-done-right/)। – lambdas

उत्तर

18

संक्षिप्त उत्तर यह है कि आप नहीं करते हैं। कारण यह है कि गुण वास्तव में केवल विधियां हैं, और यदि आप रिटर्न प्रकार को बदलने का प्रयास करते हैं, तो आपको यह मिलता है:

  • (UIView *) देखें;
  • (MyView *) देखें;

ऑब्जेक्टिव-सी नहीं अनुमति देते हैं वापसी प्रकार सहप्रसरण करता है।

आप क्या कर सकते हैं एक नई संपत्ति "myView" जोड़ें, और इसे बस "दृश्य" संपत्ति टाइप करें। यह आपके पूरे कोड में टाइपकास्ट को कम करेगा। बस व्यू प्रॉपर्टी पर अपना व्यू सबक्लास असाइन करें, और सब कुछ ठीक काम करना चाहिए।

+0

+1 मैंने जो जवाब दिया उससे बिल्कुल लापता भागों को देने के लिए :) –

4

UIViewController की दृश्य संपत्ति/विधि स्वचालित रूप से आपका दृश्य वापस कर देगी। मुझे लगता है कि तुम सिर्फ MyView के लिए परिणाम कास्ट करने के लिए (या बस id प्रकार का उपयोग करें) होगा:

MyView *myView = (MyView*)controller.view; 
id myView = controller.view; 

मुझे लगता है कि कोड आप ऊपर पोस्ट किया है आप मुसीबत का कारण होगा। आप शायद स्वयं को एक व्यू सदस्य बनाना नहीं चाहते हैं (क्योंकि तब नियंत्रक 2 विचारों को संग्रहीत करेगा, और आंतरिक रूप से सही तरीके से उपयोग नहीं करेगा) या व्यू प्रॉपर्टी को ओवरराइड करें (क्योंकि UIViewController के लिए विशेष हैंडलिंग है।) (this question देखें उत्तरार्द्ध के बारे में अधिक जानकारी के लिए।)

4

क्षमा करें, लेकिन आपका संक्षिप्त उत्तर गलत है।

इसका सही कार्यान्वयन आपके रिटर्न प्रकार के साथ हेडर फ़ाइल में @property जोड़ने के लिए होगा। तो बजाय @synthesize आप गेटर और सेटर मैन्युअल रूप से जोड़ने और [सुपर दृश्य]

उदाहरण के लिए

मेरी कक्षा एक PlayerViewController

PlayerViewController.h

@property (strong, nonatomic) IBOutlet PlayerView *view; 

PlayerViewController है से एक डाली प्रकार वापसी की। एम

- (PlayerView *)view{ 
    return (PlayerView*)[super view]; 
} 
- (void)setView:(PlayerView *)view{ 
    [super setView:view]; 
} 

महत्वपूर्ण बात सही वर्ग को देखने में रखना है।

एक UIView डालने जहां एक प्लेयर व्यू चला जाता है, इंटरफ़ेस बिल्डर में काम करेगा, लेकिन कोड में सही ढंग से कार्य नहीं करेगा।

मैं वर्तमान में इस कार्यान्वयन का उपयोग कर रहा हूं।

+0

मुझे पता है कि यह सवाल पुराना था। लेकिन मुझे यह मिला और फिर मेरे अपने जवाब के साथ आया। उम्मीद है कि यह भविष्य के उपयोगकर्ताओं की मदद करेगा। –

+0

क्या आपको लगता है कि संपत्ति मजबूत होनी चाहिए? मेरा मतलब है, 'UIView' में पहले से ही मजबूत संपत्ति' दृश्य' है जो समान मान रखती है। क्या रीडोनली संशोधक अधिक उपयुक्त नहीं है? – lambdas

+0

+1: मैंने सोचा कि यह संभव था। इसकी पुष्टि करने के लिए धन्यवाद। @ lpaul7 - नहीं, 'readonly' समझ में नहीं आता है क्योंकि तब आप 'view' प्रॉपर्टी सेट करने में सक्षम नहीं हो सकते- इसलिए 'readonly' का अर्थ। सुपरक्लास 'व्यू 'संपत्ति को ओवरराइड करने के लिए आपको इस संपत्ति को' strong' के रूप में रखना होगा (जिसमें 'strong' की संपत्ति घोषणा है)। –

23

@ lpaul7 पहले से ही एक टिप्पणी के रूप में ट्रैविस जेफ़री के ब्लॉग के लिए एक लिंक पोस्ट किया है, लेकिन यह इतना अधिक सभी अन्य उत्तर की तुलना में सही कि यह वास्तव में एक जवाब होना करने के लिए कोड की जरूरत है:

ViewController.h:

@interface ViewController : UIViewController 

@property (strong, nonatomic) UIScrollView *view; 

@end 

ViewController.m:

@implementation ViewController 

@dynamic view; 

- (void)loadView { 
    self.view = [[UIScrollView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]]; 
} 

@end 

यदि आप x12 का उपयोग करते हैं, तो loadView ओवरराइड करने के बजाय अपने व्यू कंट्रोलर के रूट व्यू के प्रकार को बदलें और IBOutlet को संपत्ति में जोड़ें।

अधिक जानकारी के लिए Overriding UIViewController's View Property, Done Right देखें।

+0

उस दृष्टिकोण का उपयोग करके मुझे निम्नलिखित कंपाइलर चेतावनी मिलती है: "संपत्ति प्रकार 'MyScrollView *' 'UIViewController' से विरासत में प्राप्त 'UIView *' प्रकार के साथ असंगत है" – Koen

+0

@Koen क्या आपका MyScrollVIV UIView का उप-वर्ग है? यदि आप MyScrollView के बजाय UIScrollView का उपयोग करते हैं तो क्या आपको संकलक चेतावनी मिलती है? – JosephH

+0

MyScrollView 'UIScrollView' का उप-वर्ग है। मैं स्क्रॉल को केवल MyCustomView के लिए एक कंटेनर देख रहा हूं जहां मैं सभी ड्राइंग करता हूं। MyScrollView के सभी चित्रों को करने के विरोध में। – Koen

0

अगर कोई स्विफ्ट 2.0+ पर है, यदि आप एक पुन: प्रयोज्य कार्यान्वयन के लिए प्रोटोकॉल एक्सटेंशन का उपयोग कर सकते हैं:

// Classes conforming to this protocol... 
protocol CustomViewProvider { 

    typealias ViewType 
} 

// ... Will get customView accessor for free 
extension CustomViewProvider where Self: UIViewController, Self.ViewType: UIView { 

    var customView: Self.ViewType { 
     return view as! Self.ViewType 
    } 
} 


// Example: 
extension HomeViewController: CustomViewProvider { 
    typealias ViewType = HomeView 
} 

// Now, we can do something like 
let customView: HomeView = HomeViewController().customView 
संबंधित मुद्दे