इंटरफ़ेस बिल्डर के साथ बनाई गई एक नीब फ़ाइल का उपयोग करके एक यूआईवीवाई को कैसे लोड करें


241

मैं कुछ विस्तृत करने की कोशिश कर रहा हूं, लेकिन कुछ ऐसा होना चाहिए जो संभव हो। तो यहाँ आप सभी विशेषज्ञों के लिए एक चुनौती है (यह मंच आप में से बहुत से लोगों का एक पैक है :))।

मैं एक प्रश्नावली "घटक" बना रहा हूं, जिसे मैं NavigationContoller(मेरे QuestionManagerViewController) पर लोड करना चाहता हूं । "घटक" एक "खाली" है UIViewController, जो उस प्रश्न के आधार पर विभिन्न विचारों को लोड कर सकता है जिसे उत्तर देने की आवश्यकता है।

जिस तरह से मैं यह कर रहा हूँ:

  1. UIViewकुछ को परिभाषित करते हुए, एक उपवर्ग के रूप में Question1View ऑब्जेक्ट बनाएं IBOutlets
  2. बनाएँ (इंटरफ़ेस बिल्डर का उपयोग करके) Question1View.xib (यहाँ क्या मेरी समस्या पूरी तरह से है )। मैंने कक्षा 1 UIViewControllerऔर 1 के दोनों UIViewप्रश्न सेट किए।
  3. मैं आउटलेट को दृश्य के घटक (आईबी का उपयोग करके) के साथ जोड़ता हूं।
  4. मैं initWithNibअपने QuestionManagerViewControllerको इस तरह देखने के लिए ओवरराइड करता हूं :

    - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
        if (self = [super initWithNibName:@"Question1View" bundle:nibBundleOrNil]) {
            // Custom initialization
        }
        return self;
    }

जब मैं कोड चलाता हूं, तो मुझे यह त्रुटि मिल रही है:

2009-05-14 15: 05: 37.152 iMobiDines [17148: 20 बी] *** बिना किसी अपवाद के कारण समाप्त होने वाला ऐप ' NSInternalInconsistencyException', कारण: ' -[UIViewController _loadViewFromNibNamed:bundle:]' प्रश्न 1 दृश्य '' को लोड किया गया था, लेकिन दृश्य आउटलेट सेट नहीं किया गया था। ''

मुझे यकीन है कि दृश्य फ़ाइल कंट्रोलर वर्ग बनाने की आवश्यकता के बिना, निब फ़ाइल का उपयोग करके दृश्य लोड करने का एक तरीका है।

जवाबों:


224

एक सरणी के रूप में निब से निपटने के बजाय दृश्य तक पहुंचने का एक आसान तरीका भी है।

1 ) किसी भी आउटलेट के साथ एक कस्टम व्यू उपवर्ग बनाएं, जिसे आप बाद में एक्सेस करना चाहते हैं। --मेरे विचार

2 ) UIViewController में, जिसे आप nib को लोड और हैंडल करना चाहते हैं, उदाहरण के लिए, लोड किए गए nib के दृश्य को धारण करने वाला IBOutlet गुण बनाएँ

MyViewController में (एक UIViewController उपवर्ग)

  @property (nonatomic, retain) IBOutlet UIView *myViewFromNib;

(इसे सिंथेसाइज़ करना न भूलें और इसे अपनी .m फ़ाइल में जारी करें)

3) आईबी में अपना एनआईबी खोलें (हम इसे 'myViewNib.xib' कहेंगे), आपने फ़ाइल का मालिक को MyViewController पर सेट किया

4) अब अपने फाइल के ओनर आउटलेट myViewFromNib को nib में मुख्य दृश्य से कनेक्ट करें।

5) अब MyViewController में, निम्नलिखित पंक्ति लिखें:

[[NSBundle mainBundle] loadNibNamed:@"myViewNib" owner:self options:nil];

अब जैसे ही आप ऐसा करते हैं, आपकी संपत्ति "self.myViewFromNib" पर कॉल करने से आपको अपने निब से दृश्य तक पहुंच मिलेगी!


4
क्या यह मुख्य नियंत्रक दृश्य (self.view) के लिए काम करेगा? कुछ कारणों से मुझे मानक नियंत्रक init विधि के बाद nib से मुख्य दृश्य लोड करने की आवश्यकता है। कारण - जटिल सबलिंग संरचना
लुकाज़

@ लुकाज़ आप इसे करने में कितना सफल हैं? यहां तक ​​कि मैं भी आप जैसी किसी चीज़ की तलाश में हूं।
अजय शर्मा

क्षमा करें मैं मोटा हो सकता हूं, लेकिन मैं पहले बिंदु पर उलझन में हूं। मैं कस्टम दृश्य उपवर्ग में आउटलेट कैसे बनाऊं? मैंने सोचा कि आउटलेट केवल UIViewControllers के लिए थे?
जूली

1
एक मामले के बारे में क्या जब यह दृश्य कई माता-पिता के विचारों पर दिखाई देता है? तो क्या आप उनमें से प्रत्येक के लिए मैन्युअल रूप से xib संपादित करने का प्रस्ताव रखते हैं? यह बहुत बुरा है!!!
user2083364

2
यह केवल तभी काम करता है जब आप एकल दृश्य नियंत्रक में कस्टम निब का उपयोग करना चाहते हैं। उस स्थिति में जहां आप इसे अलग-अलग दृश्य नियंत्रकों पर उपयोग करना चाहते हैं, प्रत्येक कस्टम नायब का एक उदाहरण गतिशील रूप से बनाते हैं, यह काम नहीं करेगा।
thgc

120

आप सभी को धन्यवाद। मुझे वह करने का तरीका मिला जो मैं चाहता था।

  1. अपनी ज़रूरत के UIViewअनुसार अपना बनाएं IBOutlet
  2. IB में xib बनाएं, इसे पसंद करने के लिए डिज़ाइन करें और इसे इस तरह लिंक करें: फ़ाइल का स्वामी वर्ग का है UIViewController(कोई कस्टम उपवर्ग नहीं, लेकिन "वास्तविक" एक)। फ़ाइल मालिक का दृष्टिकोण मुख्य दृश्य से जुड़ा है और इसकी कक्षा को चरण 1 से घोषित किया गया है)।
  3. IBOutletएस के साथ अपने नियंत्रण कनेक्ट करें ।
  4. DynamicViewControllerक्या लोड करने के लिए देखने / xib तय करने के लिए अपने तर्क चला सकते हैं। एक बार जब इसका विखंडन हो जाता है, तो loadViewविधि में कुछ इस तरह होता है:

    NSArray* nibViews = [[NSBundle mainBundle] loadNibNamed:@"QPickOneView"
                                                      owner:self
                                                    options:nil];
    
    QPickOneView* myView = [ nibViews objectAtIndex: 1];
    
    myView.question = question;

बस!

मुख्य बंडल की loadNibNamedविधि दृश्य को शुरू करने और कनेक्शन बनाने का ख्याल रखेगी।

अब ViewController स्मृति में डेटा के आधार पर एक दृश्य या कोई अन्य प्रदर्शित कर सकता है, और "पैरेंट" स्क्रीन को इस तर्क के साथ परेशान करने की आवश्यकता नहीं है।


2
मेरे पास एक समान समस्या है - मैं बस एक xib फ़ाइल से एक UIView लोड करना चाहता हूं। ये चरण मेरे लिए काम नहीं करते हैं - लोड किए गए दृश्य को उप-भाग के रूप में जोड़ने के तुरंत बाद ऐप "खराब पहुंच" के साथ क्रैश हो जाता है।
जूलरी

2
IPhone 3.0 के लिए, पहले तत्व को प्राप्त करने के लिए objectAtIndex: 0 का उपयोग करें। यह मेरे लिए ठीक वैसे ही दुर्घटनाग्रस्त होता है जैसा कि जस्टिकल द्वारा वर्णित है। कोई विचार क्यों?
tba

1
+1 यह मेरे लिए पूरी तरह से काम करता है। मैं कई व्यूज जोड़ना चाहता था जिसमें एक व्यू कंट्रोलर था (एक फ्लिप व्यू परिदृश्य का उपयोग करके जहां व्यू का एक भाग घूमता है) मुझे एरे 0 (आईफोन 3.0) पर इंडेक्स बनाना था
अरन मुल्होलैंड

42
यह सही उत्तर है, हालांकि, कोड को संशोधित किया जाना चाहिए ताकि यह nibViews के माध्यम से लूप हो और प्रत्येक ऑब्जेक्ट पर एक क्लास चेक करता है, जिससे आपको निश्चित रूप से सही ऑब्जेक्ट मिल रहा है। objectAtIndex: 1 एक खतरनाक धारणा है।
एम। रयान

2
जसकोनियस सही है। आपको इस तरह nibViews सरणी के माध्यम से लूप करना चाहिए: gist.github.com/769539
लेविथान

71

मुझे यकीन नहीं है कि कुछ उत्तर किस बारे में बात कर रहे हैं, लेकिन अगली बार Google में खोज करने पर मुझे यह उत्तर देने की आवश्यकता है। कीवर्ड: "कैसे एक निब से उइवे को लोड करें" या "एनएसबंडले से एक उविव को कैसे लोड करें।"

यहाँ कोड लगभग 100% सीधे शुरुआत iPhone 3 किताब (पृष्ठ 247, "नई तालिका दृश्य सेल का उपयोग करके"):

- (void)viewDidLoad {
    [super viewDidLoad];
    NSArray *bundle = [[NSBundle mainBundle] loadNibNamed:@"Blah"
                                                 owner:self options:nil];
    Blah *blah;
    for (id object in bundle) {
        if ([object isKindOfClass:[Blah class]]) {
            blah = (Blah *)object;
            break;
        }
    }   
    assert(blah != nil && "blah can't be nil");
    [self.view addSubview: blah];
} 

इसका मतलब है कि आपके पास एक UIViewउपवर्ग है Blah, एक नीब जिसे कहा जाता है Blahजिसमें एक UIViewवर्ग होता है Blah


श्रेणी: NSObject + LoadFromNib

#import "NSObject+LoadFromNib.h"

@implementation NSObject (LoadFromNib)

+ (id)loadFromNib:(NSString *)name classToLoad:(Class)classToLoad {
    NSArray *bundle = [[NSBundle mainBundle] loadNibNamed:name owner:self options:nil];
    for (id object in bundle) {
        if ([object isKindOfClass:classToLoad]) {
            return object;
        }
    }
    return nil;
}

@end

स्विफ्ट एक्सटेंशन

extension UIView {
    class func loadFromNib<T>(withName nibName: String) -> T? {
        let nib  = UINib.init(nibName: nibName, bundle: nil)
        let nibObjects = nib.instantiate(withOwner: nil, options: nil)
        for object in nibObjects {
            if let result = object as? T {
                return result
            }
        }
        return nil
    }
}

और उपयोग में एक उदाहरण:

class SomeView: UIView {
    class func loadFromNib() -> SomeView? {
        return self.loadFromNib(withName: "SomeView")
    }
}

2
यदि आप उपयोग करते हैं isKindOfतो आप बंडल संरचना परिवर्तनों से सुरक्षित हैं।
डैन रोसेनस्टार्क

1
एक assertशायद एक बेहतर समाधान होगा। इस तरह आप केवल समस्या को छिपाएंगे।
सुल्तान

1
@ सुल्तान का दावा अलग है। मैं निब में जहाँ भी बैठता हूं, वहां ब्ला का प्रकार चाहता हूं । मुझे परवाह नहीं है अगर यह पदोन्नत या पदावनत हो गया। हालाँकि, आपकी टिप्पणी के जवाब में मैंने एक जोर दिया है, लेकिन यह लूप के स्थान पर नहीं है for। यह उसका पूरक है।
दान रोसेनस्टार्क

आप कोई पैरामीटर के साथ loadFromNib कर सकते हैं: + (id) loadFromNib {NSArray * बंडल = [[NSBundle mainBundle] loadNibNamed: NSStringFromClass ([स्व वर्ग]) स्वामी: स्व विकल्प: nil]; for (आईडी ऑब्जेक्ट बंडल में) {if ([ऑब्जेक्ट .KindOfClass: [स्वयं वर्ग]]) {वापसी ऑब्जेक्ट; }} वापसी nil; }
JVC

22

उन सभी के लिए जिन्हें कस्टम दृश्य के एक से अधिक उदाहरणों को प्रबंधित करने की आवश्यकता है, वह है आउटलेट कलेक्शन , मैंने विलय किया और इस तरह से @Gonso, @AVeryDev और @Olie उत्तर अनुकूलित किए:

  1. एक कस्टम बनाएं MyView : UIViewऔर इसे वांछित XIB में रूट के " कस्टम क्लास " के रूप में सेट करें ; UIViewकस्टम वर्ग

  2. सभी आउटलेट्स बनाएं MyViewजिनकी आपको आवश्यकता है (इसे अभी करें क्योंकि बिंदु 3 के बाद आईबी आपको आउटलेट को कनेक्ट करने का प्रस्ताव देगा UIViewControllerऔर कस्टम दृश्य के लिए नहीं जैसा कि हम चाहते हैं); कस्टम वर्ग आउटलेट

  3. कस्टम दृश्य XIB केUIViewController " फ़ाइल स्वामी " के रूप में सेट करें ; यहां छवि विवरण दर्ज करें

  4. में UIViewControllerएक नया जोड़ने UIViewsके प्रत्येक उदाहरण के लिए MyViewयदि आप चाहते हैं, और उन्हें करने के लिए कनेक्ट UIViewControllerएक बनाने आउटलेट संग्रह : इन विचारों कस्टम दृश्य उदाहरण के लिए "आवरण" विचारों के रूप में कार्य करेगा; यहां छवि विवरण दर्ज करें

  5. अंत में, viewDidLoadअपने UIViewControllerमें निम्नलिखित पंक्तियाँ जोड़ें:

NSArray *bundleObjects;
MyView *currView;
NSMutableArray *myViews = [NSMutableArray arrayWithCapacity:myWrapperViews.count];
for (UIView *currWrapperView in myWrapperViews) {
    bundleObjects = [[NSBundle mainBundle] loadNibNamed:@"MyView" owner:self options:nil];
    for (id object in bundleObjects) {
        if ([object isKindOfClass:[MyView class]]){
            currView = (MyView *)object;
            break;
        }
    }

    [currView.myLabel setText:@"myText"];
    [currView.myButton setTitle:@"myTitle" forState:UIControlStateNormal];
    //...

    [currWrapperView addSubview:currView];
    [myViews addObject:currView];
}
//self.myViews = myViews; if need to access them later..

हाय ... आप जानते हैं कि यह सब कैसे किया जाता है। नहीं xib फ़ाइल का उपयोग करके?
एक्स-कोडर

19

मैं यूआईएनईबी का इस्तेमाल एक कस्टम यूआईईयूवी को फिर से उपयोग में लाने के लिए करेगा

UINib *customNib = [UINib nibWithNibName:@"MyCustomView" bundle:nil];
MyCustomViewClass *customView = [[customNib instantiateWithOwner:self options:nil] objectAtIndex:0];
[self.view addSubview:customView];

इस मामले में आवश्यक फाइलें MyCustomView.xib , MyCustomViewClass.h और MyCustomViewClass.m हैं। ध्यान दें कि [UINib instantiateWithOwner]एक सरणी देता है, इसलिए आपको उस तत्व का उपयोग करना चाहिए जो उस UIView को दर्शाता है जिसे आप फिर से उपयोग करना चाहते हैं। इस मामले में यह पहला तत्व है।


1
क्या आपको "रैंकिंगनैब" के बजाय लाइन 2 में "customNib" का मतलब नहीं है
डैनी

11

आपको UIViewइंटरफ़ेस बिल्डर में उपवर्ग होने के लिए अपने व्यू कंट्रोलर की श्रेणी निर्धारित नहीं करनी चाहिए । यह निश्चित रूप से आपकी समस्या का कम से कम हिस्सा है। या तो UIViewControllerइसे छोड़ दें , इसके कुछ उपवर्ग, या आपके पास कुछ अन्य कस्टम वर्ग।

एक xib से केवल एक दृश्य लोड करने के लिए के रूप में, मैं इस धारणा के तहत किया गया है कि आप था दृश्य नियंत्रक (भले ही यह विस्तार नहीं करता है किसी प्रकार का है करने के लिए UIViewControllerहै, जो आपकी आवश्यकताओं के लिए भी भारी-भरकम हो सकता है) इंटरफ़ेस में फ़ाइल के स्वामी के रूप में सेट बिल्डर यदि आप इसे अपने इंटरफ़ेस को परिभाषित करने के लिए उपयोग करना चाहते हैं। मैंने इसकी पुष्टि करने के लिए थोड़ा शोध किया। ऐसा इसलिए है क्योंकि अन्यथा इंटरफ़ेस तत्वों में से किसी को एक्सेस करने का कोई तरीका नहीं होगा UIView, और न ही घटनाओं के कारण कोड में अपने तरीके रखने का कोई तरीका होगा।

यदि आप UIViewControllerअपने फाइल के मालिक के रूप में अपने विचारों के लिए उपयोग करते हैं, तो आप initWithNibName:bundle:इसे लोड करने और व्यू कंट्रोलर ऑब्जेक्ट को वापस पाने के लिए उपयोग कर सकते हैं । IB में, सुनिश्चित करें कि आपने viewxib में अपने इंटरफ़ेस के साथ दृश्य पर आउटलेट सेट किया है । आप अपनी फ़ाइल के स्वामी के रूप में वस्तु के कुछ अन्य प्रकार का उपयोग करें, तो आप का उपयोग करना होगा NSBundleकी loadNibNamed:owner:options:विधि के लिए फ़ाइल के मालिक का एक उदाहरण गुजर, निब लोड करने के लिए विधि। इसके सभी गुण आईबी में परिभाषित आउटलेट्स के अनुसार ठीक से सेट किए जाएंगे।


मैं एप्रेस किताब पढ़ रहा हूं, "बिगिनिंग आईफोन डेवलपमेंट: एक्सप्लोरिंग द आईफोन एसडीके" और उन्होंने इस विधि की चर्चा अध्याय 9: नेविगेशन कंट्रोलर्स और टेबल व्यू में की। यह बहुत जटिल नहीं लगता था।
लिंडसे फर्ग्यूसन

मैं यह देखने के लिए उत्सुक हूं कि वे यह कैसे करते हैं। मेरे पास उस समय उस पुस्तक की प्रति नहीं है।
मार्क डब्ल्यू

10

तुम भी लोड के बजाय UIViewController initWithNibName का उपयोग कर सकते हैं। यह आसान है, मुझे लगता है।

UIViewController *aViewController = [[UIViewController alloc] initWithNibName:@"MySubView" bundle:nil];
[self.subview addSubview:aViewController.view];
[aViewController release];  // release the VC

अब आपको बस MySubView.xib और MySubView.h / m बनाना होगा। MySubView.xib में फ़ाइल के मालिक वर्ग को UIViewController के लिए सेट करें और MySubView को वर्ग देखें।

आप subviewपैरेंट xib फ़ाइल का उपयोग करने की स्थिति और आकार कर सकते हैं ।


8

यह एक महान प्रश्न है (+1) और उत्तर लगभग मददगार थे ;) क्षमा करें दोस्तों, लेकिन मेरे पास इसके माध्यम से नारा लगाने की एक समय की ऊँचाई थी, हालांकि गोनसो और एवेरीडेव दोनों ने अच्छे संकेत दिए। उम्मीद है, यह जवाब दूसरों की मदद करेगा।

MyVC यह सब सामान रखने वाला कंट्रोलर है।

MySubview वह दृश्य है जिसे हम एक xib से लोड करना चाहते हैं

  • MyVC.xib में, MySubViewउस प्रकार का एक दृश्य बनाएं जो सही आकार और आकृति है और जिसे आप चाहते हैं, वहां तैनात किया गया है।
  • MyVC.h में है

    IBOutlet MySubview *mySubView
    // ...
    @property (nonatomic, retain) MySubview *mySubview;
  • MyVC.m में, @synthesize mySubView;और इसे जारी करने के लिए मत भूलना dealloc

  • MySubview.h में, के लिए एक आउटलेट / संपत्ति है UIView *view हो सकती है (अनावश्यक हो सकती है, लेकिन मेरे लिए काम किया है।) इसे सिंथेसाइज़ और रिलीज़ करें।
  • MySubview.xib में
    • फ़ाइल स्वामी प्रकार को सेट करें MySubview, और दृश्य संपत्ति को अपने दृश्य से लिंक करें।
    • सभी बिट्स बाहर रखना और IBOutletवांछित के रूप में कनेक्ट करें
  • MyVC.m में वापस, है

    NSArray *xibviews = [[NSBundle mainBundle] loadNibNamed: @"MySubview" owner: mySubview options: NULL];
    MySubview *msView = [xibviews objectAtIndex: 0];
    msView.frame = mySubview.frame;
    UIView *oldView = mySubview;
    // Too simple: [self.view insertSubview: msView aboveSubview: mySubview];
    [[mySubview superview] insertSubview: msView aboveSubview: mySubview]; // allows nesting
    self.mySubview = msView;
    [oldCBView removeFromSuperview];

मेरे लिए मुश्किल सा था: अन्य उत्तरों में संकेतों ने मेरे विचार को xib से लोड किया था, लेकिन MyVC (duh!) में दृश्य को प्रतिस्थापित नहीं किया था - मुझे अपने आप से बाहर स्वैप करना था।

इसके अलावा, mySubview's तरीकों तक पहुँचने के लिए , view.xib फ़ाइल में गुण सेट करना होगा MySubview। अन्यथा, यह एक सादे-पुराने के रूप में वापस आता है UIView

यदि mySubviewअपने स्वयं के xib से सीधे लोड करने का कोई तरीका है , तो वह रॉक करेगा, लेकिन यह मुझे वहां मिला जहां मुझे होना चाहिए।


1
मैंने इस विधि का उपयोग किया, धन्यवाद। एक परिवर्तन मैं इसे समर्थन करने के लिए नेस्टेड दृश्य [बदलने के लिए था अनुमति देने के लिए बनाया self.view : msView aboveSubview: insertSubview mySubview]; [ mySubview.superview सम्मिलित करें: साक्षात्कार: msView ऊपर का दृश्य: mySubview];
जेसन

8

यह कुछ ऐसा है जो आसान होना चाहिए। मैंने चयनकर्ता का विस्तार करना UIViewControllerऔर जोड़ना समाप्त कर दिया loadNib:inPlaceholder:। अब मैं कह सकता हूं

self.mySubview = (MyView *)[self loadNib:@"MyView" inPlaceholder:mySubview];

यहाँ श्रेणी के लिए कोड है (यह गोनसो द्वारा वर्णित के रूप में एक ही रिगामालेर करता है):

@interface UIViewController (nibSubviews)

- (UIView *)viewFromNib:(NSString *)nibName;
- (UIView *)loadNib:(NSString *)nibName inPlaceholder:(UIView *)placeholder;

@end

@implementation UIViewController (nibSubviews)

- (UIView *)viewFromNib:(NSString *)nibName
{
  NSArray *xib = [[NSBundle mainBundle] loadNibNamed:nibName owner:self options:nil]; 
  for (id view in xib) { // have to iterate; index varies
    if ([view isKindOfClass:[UIView class]]) return view;
  }
  return nil;
}

- (UIView *)loadNib:(NSString *)nibName inPlaceholder:(UIView *)placeholder
{
  UIView *nibView = [self viewFromNib:nibName];
  [nibView setFrame:placeholder.frame];
  [self.view insertSubview:nibView aboveSubview:placeholder];
  [placeholder removeFromSuperview];
  return nibView;
}

@end

7

स्विफ्ट में

वास्तव में इस समस्या का मेरा संकल्प था, मेरे CustonViewController में एक दृश्य में दृश्य लोड करने के लिए जहां मैं उस तरह के दृश्य का उपयोग करना चाहता था:

myAccessoryView = NSBundle.mainBundle().loadNibNamed("MyAccessoryView", owner: self, options: nil)[0] as! MyAccessoryView

एक loadView()विधि में दृश्य लोड न करें ! लोड व्यू पद्धति आपके कस्टम व्यूकंट्रोलर के लिए दृश्य लोड करने के लिए कार्य करती है।


6

मैं भी कुछ ऐसा ही करना चाहता था, यही मैंने पाया: (एसडीके 3.1.3)

मेरे पास एक व्यू कंट्रोलर A है (खुद एक नव कंट्रोलर के पास) जो एक बटन प्रेस पर VC B लोड करता है:

AViewController.m में

BViewController *bController = [[BViewController alloc] initWithNibName:@"Bnib" bundle:nil];
[self.navigationController pushViewController:bController animated:YES];
[bController release];

अब VC B का Bnib से इसका इंटरफ़ेस है, लेकिन जब एक बटन दबाया जाता है, तो मैं एक 'edit mode' में जाना चाहता हूँ, जिसमें अलग-अलग nib से अलग UI है, लेकिन मुझे edit mode के लिए नया VC नहीं चाहिए, मैं चाहता हूं कि नया nib मेरे मौजूदा B VC के साथ जुड़ा हो।

तो, BViewController.m में (बटन प्रेस विधि में)

NSArray *nibObjects = [[NSBundle mainBundle] loadNibNamed:@"EditMode" owner:self options:nil];
UIView *theEditView = [nibObjects objectAtIndex:0];
self.editView = theEditView;
[self.view addSubview:theEditView];

फिर दूसरे बटन प्रेस पर (संपादन मोड से बाहर निकलने के लिए):

[editView removeFromSuperview];

और मैं अपने मूल Bnib पर वापस आ गया हूं।

यह ठीक काम करता है, लेकिन ध्यान दें मेरे EditMode.nib में केवल 1 शीर्ष स्तर obj है, एक UIView obj। इससे कोई फर्क नहीं पड़ता कि इस nib में फ़ाइल का मालिक BViewController या डिफ़ॉल्ट NSObject के रूप में सेट किया गया है, लेकिन यह सुनिश्चित करें कि फ़ाइल के स्वामी में व्यू आउटलेट कुछ भी सेट नहीं है। यदि यह है, तो मुझे एक exc_bad_access दुर्घटना मिलती है और 6677 स्टैक फ्रेम को लोड करने के लिए एक्सकोड एक्सीडेस मिलता है, जो एक आंतरिक यूआईवीयूवी विधि दिखा रहा है जिसे बार-बार कहा जाता है ... इसलिए एक अनंत लूप जैसा दिखता है। (हालांकि, मेरे मूल Bnib में सेट आउटलेट देखें)

उम्मीद है की यह मदद करेगा।


रेखाओं के बीच पढ़ने से मुझे इससे भी मदद मिली।
पेट्रो

लिंक पर मौजूद जानकारी के अनुसार आपको इस तरह से व्यू कंट्रोलर में हेरफेर नहीं करना चाहिए।
टी। मार्कले

6

मैंने एक श्रेणी बनाई जो मुझे पसंद है:

UIView+NibInitializer.h

#import <UIKit/UIKit.h>

@interface UIView (NibInitializer)
- (instancetype)initWithNibNamed:(NSString *)nibNameOrNil;
@end

UIView+NibInitializer.m

#import "UIView+NibInitializer.h"

@implementation UIView (NibInitializer)

- (instancetype)initWithNibNamed:(NSString *)nibNameOrNil
{
    if (!nibNameOrNil) {
        nibNameOrNil = NSStringFromClass([self class]);
    }
    NSArray *viewsInNib = [[NSBundle mainBundle] loadNibNamed:nibNameOrNil
                                                        owner:self
                                                      options:nil];
    for (id view in viewsInNib) {
        if ([view isKindOfClass:[self class]]) {
            self = view;
            break;
        }
    }
    return self;
}

@end

फिर, इस तरह से कॉल करें:

MyCustomView *myCustomView = [[MyCustomView alloc] initWithNibNamed:nil];

यदि आपके निब का नाम आपके वर्ग के नाम के अलावा कुछ और है तो निब नाम का उपयोग करें।

अतिरिक्त व्यवहार के लिए इसे अपने उपवर्गों में ओवरराइड करने के लिए, यह इस तरह दिख सकता है:

- (instancetype)initWithNibNamed:(NSString *)nibNameOrNil
{
    self = [super initWithNibNamed:nibNameOrNil];
    if (self) {
        self.layer.cornerRadius = CGRectGetHeight(self.bounds) / 2.0;
    }
    return self;
}

5

डिज़ाइन करने योग्य विकल्प के साथ स्विफ्ट उपयोगकर्ता के लिए:

  1. एक कस्टम UIViewउपवर्ग और एक xib फ़ाइलें बनाएँ , जिसे हम अपने स्वयं के वर्ग नाम के बाद नाम देंगे: हमारे मामले में MemeView। मेमे व्यू वर्ग के अंदर @IBDesignableवर्ग घोषणा से पहले विशेषता के साथ इसे डिजाइन के रूप में परिभाषित करना याद रखें
  2. इंडस्ट्रीज़ UIViewइंस्पेक्टर पैनल में हमारे कस्टम उपवर्ग के साथ xib में फ़ाइल के मालिक को सेट करने के लिए इकट्ठा

    यहां छवि विवरण दर्ज करें

  3. Xib फाइल में अब हम अपना इंटरफेस बना सकते हैं, अड़चन बना सकते हैं, आउटलेट, एक्शन आदि बना सकते हैं। यहां छवि विवरण दर्ज करें

  4. हमें एक बार आरंभिक रूप से xib खोलने के लिए अपने कस्टम वर्ग में कुछ विधियों को लागू करने की आवश्यकता है

    class XibbedView: UIView {

    weak var nibView: UIView!
    
    override convenience init(frame: CGRect) {
        let nibName = NSStringFromClass(self.dynamicType).componentsSeparatedByString(".").last!
        self.init(nibName: nibName)
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        let nibName = NSStringFromClass(self.dynamicType).componentsSeparatedByString(".").last!
        let nib = loadNib(nibName)
        nib.frame = bounds
        nib.translatesAutoresizingMaskIntoConstraints = false
        addSubview(nib)
        nibView = nib
        setUpConstraints()
    }
    
    init(nibName: String) {
        super.init(frame: CGRectZero)
        let nibName = NSStringFromClass(self.dynamicType).componentsSeparatedByString(".").last!
        let nib = loadNib(nibName)
        nib.frame = bounds
        nib.translatesAutoresizingMaskIntoConstraints = false
        addSubview(nib)
        nibView = nib
        setUpConstraints()
    }
    
    func setUpConstraints() {
        ["V","H"].forEach { (quote) -> () in
            let format = String(format:"\(quote):|[nibView]|")
            addConstraints(NSLayoutConstraint.constraintsWithVisualFormat(format, options: [], metrics: nil, views: ["nibView" : nibView]))
        }
    }
    
    func loadNib(name: String) -> UIView {
        let bundle = NSBundle(forClass: self.dynamicType)
        let nib = UINib(nibName: name, bundle: bundle)
        let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
    
        return view
    }

    }

  5. हमारे कस्टम वर्ग में हम इंटरफ़ेस निर्माता से उन पर पूर्ण नियंत्रण रखने के लिए कुछ निरीक्षण योग्य गुणों को भी परिभाषित कर सकते हैं

    @IBDesignable class MemeView: XibbedView {

    @IBInspectable var memeImage: UIImage = UIImage() {
        didSet {
            imageView.image = memeImage
        }
    }
    @IBInspectable var textColor: UIColor = UIColor.whiteColor() {
        didSet {
            label.textColor = textColor
        }
    }
    @IBInspectable var text: String = "" {
        didSet {
            label.text = text
        }
    }
    @IBInspectable var roundedCorners: Bool = false {
        didSet {
            if roundedCorners {
                layer.cornerRadius = 20.0
                clipsToBounds = true
            }
            else {
                layer.cornerRadius = 0.0
                clipsToBounds = false
            }
        }
    }
    
    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var imageView: UIImageView!

}

कुछ उदाहरण:
यहां छवि विवरण दर्ज करें यहां छवि विवरण दर्ज करें

अगर हमें स्टोरीबोर्ड या किसी अन्य xib के अंदर प्रदर्शित होने के दौरान अधिक जानकारी जोड़ने की आवश्यकता है, तो हम इसे लागू कर सकते हैं prepareForInterfaceBuilder() , इस पद्धति को केवल इंटरफ़ेस बिल्डर में फ़ाइल खोलने के दौरान निष्पादित किया जाएगा। यदि आपने जो कुछ भी लिखा है, वह सब किया है, लेकिन काम नहीं कर रहा है, तो इसके कार्यान्वयन में ब्रेकप्वाइंट जोड़कर एक बड़े दृश्य को डीबग करने का एक तरीका है। यहाँ दृश्य पदानुक्रम है। यहां छवि विवरण दर्ज करें
देखिए नमस्ते

आशा है कि यह एक पूर्ण नमूना यहाँ डाउनलोड करने में मदद करता है


पूरा लेख मेरे ब्लॉग cloudintouch.it/2016/04/21/designable-xib-in-xcode-hell-yeah से देखा जा सकता है, लेकिन मैंने पहले ही संबंधित भाग पोस्ट कर दिया है।
एंड्रिया

let nib = loadNib(nibName)यह एक XibbedView उदाहरण है, यदि आप `` addSubview (nib) `` कहते हैं, तो आप एक XibbedView उदाहरण को दूसरे XibbedView उदाहरण में जोड़ रहे हैं?
विलियम हू

मैं इस बात पर सहमत हूं। जब आप इसे "डिबग व्यू पदानुक्रम" से देखने का प्रयास करते हैं तो लगता है कि XibbedView में XibbedView शामिल है। तुम देख सकते हो।
विलियम हू

@WilliamHu यदि आप प्रदान किए गए उदाहरण को लोड नहीं करते हैं, तो आप देख सकते हैं कि MemeView.xib सबवेक्शंस के एक समूह के साथ सिर्फ एक UIView उदाहरण है, फ़ाइल धारक एक मेमव्यू है जो XibbedView का एक उपवर्ग है। इस प्रकार XibbedView का एकमात्र उदाहरण सिर्फ MemeView है जो एक xib फ़ाइल को लोड करता है जहां मुख्य दृश्य सिर्फ एक दृश्य है
एंड्रिया

ओह फिर ठीक है। मैं इसका परीक्षण करूंगा। धन्यवाद!
विलियम हू

4

मुझे यह ब्लॉग आरोन हिलेगस (लेखक, प्रशिक्षक, कोको निंजा) द्वारा पोस्ट करने के लिए बहुत ज्ञानवर्धक लगा। यहां तक ​​कि अगर आप एनआईबी फ़ाइलों को एक निर्दिष्ट इनिशलाइज़र के माध्यम से लोड करने के लिए अपने संशोधित दृष्टिकोण को नहीं अपनाते हैं, तो संभवतः आपको कम से कम प्रक्रिया की बेहतर समझ मिल जाएगी। मैं महान सफलता के लिए हाल ही में इस विधि का उपयोग कर रहा हूँ!


लिंक मर चुका है। मेरा मानना ​​है कि यह अब bignerdranch.com/blog/…
joelliusp

3

पिछला उत्तर iPhone SDK के 2.0 और 2.1 के बीच होने वाले NIB (XIB) संरचना में बदलाव को ध्यान में नहीं रखता है। उपयोगकर्ता सामग्री अब 1 के बजाय सूचकांक 0 से शुरू होती है।

आप 2.1 मैक्रो का उपयोग कर सकते हैं जो सभी संस्करण 2.1 और इसके बाद के संस्करण के लिए मान्य है (यह IPHONE से पहले दो अंडरस्कोर है:

 // Cited from previous example
 NSArray* nibViews =  [[NSBundle mainBundle] loadNibNamed:@"QPickOneView" owner:self options:nil];
 int startIndex;
 #ifdef __IPHONE_2_1
 startIndex = 0;
 #else
 startIndex = 1;
 #endif
 QPickOneView* myView = [ nibViews objectAtIndex: startIndex];
 myView.question = question;

हम अपने अधिकांश अनुप्रयोगों के लिए इसी तरह की तकनीक का उपयोग करते हैं।

बार्नी


2
बार्नी: स्टैक ओवरफ्लो पर "पिछला जवाब" निरर्थक है क्योंकि उत्तर मतदान के आधार पर बदलाव की स्थिति है। "फ्रेड के उत्तर" या "बार्नी के उत्तर" या "ओली के उत्तर" को संदर्भित करने के लिए बेहतर है।
ओली

3

मेरे पास एक ही काम करने का कारण था (प्रोग्रामेटिक रूप से एक XIB फ़ाइल से दृश्य लोड करना), लेकिन मुझे यह पूरी तरह से एक उपवर्ग के उपवर्ग के संदर्भ से करने की आवश्यकता थी UIView(अर्थात किसी भी तरह से दृश्य नियंत्रक को शामिल किए बिना)। ऐसा करने के लिए मैंने यह उपयोगिता विधि बनाई:

+ (id) initWithNibName:(NSString *)nibName withSelf:(id)myself {

    NSArray *bundle = [[NSBundle mainBundle] loadNibNamed:nibName
                                                    owner:myself options:nil];
    for (id object in bundle) {
        if ([object isKindOfClass:[myself class]]) {
            return object;
        }
    }  

    return nil;
} 

तब मैं इसे अपने उपवर्ग initWithFrameविधि से कहता हूं जैसे:

- (id)initWithFrame:(CGRect)frame {

    self = [Utilities initWithNibName:@"XIB1" withSelf:self];
    if (self) {
        // Initialization code.
    }
    return self;
}

सामान्य हित के लिए पोस्ट किया गया; अगर किसी को इस तरह से बिना किसी समस्या के देखता है, तो कृपया मुझे बताएं।


मैंने आपका कोड लागू कर दिया है, लेकिन यह init पर स्कोप से बाहर जा रहा है। मैंने यूटिलिटीज क्लास में आपका स्टैटिक तरीका बनाया। मैंने MyView नामक U / m फाइलें (UIView से उप-वर्ग) बनाईं और एक xib नाम दिया। IB में मैंने xib फ़ाइलों के स्वामी और "MyView" पर दृश्य सेट किया है। डिबगर में यह दायरे से बाहर है। क्या मुझे IB में कुछ याद आ रहा है?
टाइगरकोडिंग

कृपया मेरे नए SO प्रश्न पर एक नज़र डालें: stackoverflow.com/questions/9224857/…
टाइगरकोडिंग

आत्म = [उपयोगिताएँ initWithNibName: @ "XIB1" withSelf: self]; जब आप अभी तक सेट नहीं हुए हैं तो आप स्वयं गुजर रहे हैं। क्या वह कोड इस प्रकार नहीं है: स्वयं = [उपयोगिताएँ initWithNibName: @ "XIB1" withSelf: nil]; ?
केन वान होएलैंड्ट

@ जेवी: यहां मेरा कोड नमूना एआरसी के साथ काम नहीं कर सकता है - मैंने एआरसी सक्षम के साथ इसका परीक्षण नहीं किया है।
19

3

यहां इसे स्विफ्ट में करने का एक तरीका है (वर्तमान में XCode 7 बीटा 5 में स्विफ्ट 2.0 लिख रहा है)।

UIViewइंटरफ़ेस बिल्डर में "कस्टम क्लास" के रूप में सेट किए जाने वाले आपके उपवर्ग से इस तरह एक विधि बनाते हैं (मेरे उपवर्ग को रिकॉर्डिंग रिकॉर्डिंग कहा जाता है):

class func loadFromNib() -> RecordingFooterView? {
    let nib = UINib(nibName: "RecordingFooterView", bundle: nil)
    let nibObjects = nib.instantiateWithOwner(nil, options: nil)
    if nibObjects.count > 0 {
        let topObject = nibObjects[0]
        return topObject as? RecordingFooterView
    }
    return nil
}

तब आप इसे इस तरह कह सकते हैं:

let recordingFooterView = RecordingFooterView.loadFromNib()


2

कोई भी उत्तर यह नहीं बताता है कि अकेले XIB को कैसे खड़ा किया जाए जो इस प्रश्न का मूल है। कोई नहीं हैXcode 4"नई XIB फ़ाइल बनाएँ" विकल्प है।

यह करने के लिए

1) Choose "New File..."
2) Choose the "User Interface" category under the iOS section
3) Choose the "View" item
4) You will then be prompted to choose an iPhone or iPad format

यह सरल लग सकता है, लेकिन यह आपको कुछ मिनटों के लिए चारों ओर से बचा सकता है क्योंकि "XIB" शब्द कहीं भी प्रकट नहीं होता है।


1

@AVeryDev

6) लोडेड व्यू को अपने व्यू कंट्रोलर के व्यू में अटैच करना:

[self.view addSubview:myViewFromNib];

संभवतः, मेमोरी लीक से बचने के लिए इसे दृश्य से हटाना आवश्यक है।

स्पष्ट करने के लिए: दृश्य नियंत्रक में कई IBOutlets होते हैं, जिनमें से कुछ मूल निब फ़ाइल (हमेशा की तरह) में आइटम से जुड़े होते हैं, और कुछ लोड किए गए निब में आइटम से जुड़े होते हैं। दोनों निब के एक ही मालिक वर्ग है। लोड किया गया दृश्य मूल को ओवरले करता है।

संकेत: लोड किए गए निब में मुख्य दृश्य की अस्पष्टता को शून्य पर सेट करें, फिर यह मूल निब से आइटम को अस्पष्ट नहीं करेगा।


बाहर देखने के लिए अच्छी बात है, लेकिन सबव्यू के रूप में एक दृश्य को जोड़ने से यह अपने पिछले माता-पिता से स्वचालित रूप से हटा देता है इसलिए इसे लीक नहीं करना चाहिए।
एवेर्देव

1

कई घंटे बिताने के बाद, मैंने निम्नलिखित समाधान किया। कस्टम बनाने के लिए इन चरणों का पालन करें UIView

1) वर्ग बनाएं MyCustomView UIView से विरासत में मिला ।
यहां छवि विवरण दर्ज करें

2) बनाएँ .xib नाम myCustomView के साथ ।
यहां छवि विवरण दर्ज करें

3) अपने .xib फ़ाइल के अंदर UIView का वर्ग बदलें , वहाँ myCustomView कक्षा असाइन करें ।
यहां छवि विवरण दर्ज करें

4) IBOutlets बनाएं
यहां छवि विवरण दर्ज करें

5) लोड .xib in myCustomView * customView । नमूना कोड का उपयोग करें।

myCustomView * myView = [[[NSBundle mainBundle] loadNibNamed:@"myCustomView" owner:self options:nil] objectAtIndex:0];
[myView.description setText:@"description"];

नोट: उन लोगों के लिए जो अभी भी समस्या का सामना कर सकते हैं, मैं उन्हें myCustomView के साथ नमूना परियोजना का लिंक प्रदान करूंगा



0

मेरे पास उन नामों के साथ xibs के नामकरण का एक सम्मेलन है, जो दृश्य के समान हैं। एक के रूप में एक ही एक दृश्य नियंत्रक के लिए करना होगा। फिर, मुझे कोड में वर्ग के नाम नहीं लिखने होंगे। मैं एक ही नाम के साथ एक निब फ़ाइल से एक UIView लोड करता हूं।

MyView नामक एक वर्ग के लिए उदाहरण।

  • इंटरफ़ेस बिल्डर में MyView.xib नामक एक निब फ़ाइल बनाएँ
  • इंटरफ़ेस बिल्डर में, एक UIView जोड़ें। इसकी कक्षा MyView पर सेट करें। अपने दिल की सामग्री के लिए कस्टमाइज़ करें, MyView के सबवेरा के इंस्टेंस वेरिएबल्स जिन्हें आप बाद में एक्सेस करना चाहते हैं।
  • अपने कोड में, इस तरह एक नया MyView बनाएं:

    MyView * myView = [MyView nib_viewFromNibWithOwner: मालिक];

इसके लिए श्रेणी इस प्रकार है:

@implementation UIView (nib)

+ (id) nib_viewFromNib {
    return [self nib_viewFromNibWithOwner:nil];
}

+ (id) nib_viewFromNibWithOwner:(id)owner {
    NSString *className = NSStringFromClass([self class]);
    NSArray *nib = [[NSBundle mainBundle] loadNibNamed:className owner:owner options:nil];
    UIView *view = nil;
    for(UIView *v in nib) {
        if ([v isKindOfClass:[self class]]) {
            view = v;
            break;
        }
    }
    assert(view != nil && "View for class not found in nib file");
    [view nib_viewDidLoad];
    return view;
}

// override this to do custom setup
-(void)nib_viewDidLoad {

}

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


0

क्रमिक रूप से स्विफ्ट 4 में nib / xib से दृश्य लोड करने के लिए:

// Load a view from a Nib given a placeholder view subclass
//      Placeholder is an instance of the view to load.  Placeholder is discarded.
//      If no name is provided, the Nib name is the same as the subclass type name
//
public func loadViewFromNib<T>(placeholder placeholderView: T, name givenNibName: String? = nil) -> T {

    let nib = loadNib(givenNibName, placeholder: placeholderView)
    return instantiateView(fromNib: nib, placeholder: placeholderView)
}

// Step 1: Returns a Nib
//
public func loadNib<T>(_ givenNibName: String? = nil, placeholder placeholderView: T) -> UINib {
    //1. Load and unarchive nib file
    let nibName = givenNibName ?? String(describing: type(of: placeholderView))

    let nib = UINib(nibName: nibName, bundle: Bundle.main)
    return nib
}

// Step 2: Instantiate a view given a nib
//
public func instantiateView<T>(fromNib nib: UINib, placeholder placeholderView: T) -> T {
    //1. Get top level objects
    let topLevelObjects = nib.instantiate(withOwner: placeholderView, options: nil)

    //2. Have at least one top level object
    guard let firstObject = topLevelObjects.first else {
        fatalError("\(#function): no top level objects in nib")
    }

    //3. Return instantiated view, placeholderView is not used
    let instantiatedView = firstObject as! T
    return instantiatedView
}

-1

मैंने इसके लिए UIView में एक श्रेणी जोड़ना समाप्त किया:

 #import "UIViewNibLoading.h"

 @implementation UIView (UIViewNibLoading)

 + (id) loadNibNamed:(NSString *) nibName {
    return [UIView loadNibNamed:nibName fromBundle:[NSBundle mainBundle] retainingObjectWithTag:1];
 }

 + (id) loadNibNamed:(NSString *) nibName fromBundle:(NSBundle *) bundle retainingObjectWithTag:(NSUInteger) tag {
    NSArray * nib = [bundle loadNibNamed:nibName owner:nil options:nil];
    if(!nib) return nil;
    UIView * target = nil;
    for(UIView * view in nib) {
        if(view.tag == tag) {
            target = [view retain];
            break;
        }
    }
    if(target && [target respondsToSelector:@selector(viewDidLoad)]) {
        [target performSelector:@selector(viewDidLoad)];
    }
    return [target autorelease];
 }

 @end

यहाँ स्पष्टीकरण: viewcontroller ios और मैक में लोड हो रहा है कम दृश्य है


मानव संसाधन विकास मंत्री। टैग के साथ क्या है?
n13

यह जानने के लिए कि किस शीर्ष स्तर की वस्तु को बनाए रखना है। उस समय यह आवश्यक था, लेकिन आप संभवतः एआरसी के अनुपालन के लिए रिटेन को निकाल सकते हैं।
gngrwzrd
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.