Carica la vista da un file xib esterno nello storyboard


131

Voglio usare una vista in più viewcontroller in uno storyboard. Pertanto, ho pensato di progettare la vista in un xib esterno in modo che i cambiamenti si riflettano in ogni viewcontroller. Ma come si può caricare una vista da un xib esterno in uno storyboard ed è anche possibile? In caso contrario, quali altre alternative sono disponibili per adattarsi alla situazione?



Risposte:


132

Il mio esempio completo è qui , ma fornirò un riepilogo di seguito.

disposizione

Aggiungi un file .swift e .xib ciascuno con lo stesso nome al tuo progetto. Il file .xib contiene il layout di visualizzazione personalizzato (preferibilmente utilizzando i vincoli di layout automatico).

Rendi il file rapido il proprietario del file xib.

inserisci qui la descrizione dell'immagine Codice

Aggiungi il seguente codice al file .swift e collega i punti vendita e le azioni dal file .xib.

import UIKit
class ResuableCustomView: UIView {

    let nibName = "ReusableCustomView"
    var contentView: UIView?

    @IBOutlet weak var label: UILabel!
    @IBAction func buttonTap(_ sender: UIButton) {
        label.text = "Hi"
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        guard let view = loadViewFromNib() else { return }
        view.frame = self.bounds
        self.addSubview(view)
        contentView = view
    }

    func loadViewFromNib() -> UIView? {
        let bundle = Bundle(for: type(of: self))
        let nib = UINib(nibName: nibName, bundle: bundle)
        return nib.instantiate(withOwner: self, options: nil).first as? UIView
    }
}

Usalo

Usa la visualizzazione personalizzata in qualsiasi punto dello storyboard. Aggiungi a UIViewe imposta il nome della classe sul nome della tua classe personalizzata.

inserisci qui la descrizione dell'immagine


3
Non è che loadNibNamed chiama init (coder :)? Ho un incidente che prova ad adattare il tuo approccio.
Fishman,

@Fishman, se provi a caricare la vista a livello di codice (anziché dallo storyboard), si arresta in modo anomalo perché al momento non ha un init(frame:). Vedi questo tutorial per maggiori dettagli.
Suragch,

7
Un'altra causa comune di arresto anomalo non è l'impostazione della vista personalizzata sul proprietario del file . Vedi il cerchio rosso nella mia risposta.
Suragch,

5
Sì, avevo impostato la classe della vista radice invece del proprietario del file e stava causando un ciclo infinito.
devios1

2
Dopo aver aggiunto la riga view.autoresizingMask = [.f flexibleWidth, .ftableHeight] prima di self.addSubview (view) funziona perfettamente.
Pramod Tapaniya,

69

Per un po ' l'approccio di Christopher Swasey fu l'approccio migliore che avessi trovato. Ho chiesto a un paio di sviluppatori senior della mia squadra e uno di loro ha avuto la soluzione perfetta ! Soddisfa tutte le preoccupazioni che Christopher Swasey ha affrontato in modo così eloquente e non richiede il codice della sottoclasse della caldaia (la mia principale preoccupazione per il suo approccio). C'è un gotcha , ma a parte questo è abbastanza intuitivo e facile da implementare.

  1. Crea una classe UIView personalizzata in un file .swift per controllare il tuo xib. vale a direMyCustomClass.swift
  2. Crea un file .xib e personalizzalo come desideri. vale a direMyCustomClass.xib
  3. Imposta il File's Ownerfile .xib come classe personalizzata ( MyCustomClass)
  4. GOTCHA: lasciare vuoto il classvalore (sotto il identity Inspector) per la visualizzazione personalizzata nel file .xib. Quindi la tua vista personalizzata non avrà una classe specificata, ma avrà il proprietario di un file specificato.
  5. Collega i tuoi punti vendita come faresti normalmente con il Assistant Editor.
    • NOTA: se guardi Connections Inspector, noterai che i tuoi punti di riferimento non fanno riferimento alla tua classe personalizzata (cioè MyCustomClass), ma piuttosto al riferimento File's Owner. Poiché File's Ownerviene specificato come classe personalizzata, le prese si collegheranno e funzioneranno correttamente.
  6. Assicurati che la tua classe personalizzata abbia @IBDesignable prima dell'istruzione di classe.
  7. Rendi la tua classe personalizzata conforme al NibLoadableprotocollo indicato di seguito.
    • NOTA: se il .swiftnome del file della classe personalizzata è diverso dal .xibnome del file, impostare la nibNameproprietà come nome del .xibfile.
  8. Implementare required init?(coder aDecoder: NSCoder)e override init(frame: CGRect)chiamare setupFromNib()come nell'esempio seguente.
  9. Aggiungi una UIView allo storyboard desiderato e imposta la classe come nome della tua classe personalizzata (ad es MyCustomClass.).
  10. Guarda IBDesignable in azione mentre disegna il tuo .xib nello storyboard con tutto il suo stupore e meraviglia.

Ecco il protocollo che vorresti fare riferimento:

public protocol NibLoadable {
    static var nibName: String { get }
}

public extension NibLoadable where Self: UIView {

    public static var nibName: String {
        return String(describing: Self.self) // defaults to the name of the class implementing this protocol.
    }

    public static var nib: UINib {
        let bundle = Bundle(for: Self.self)
        return UINib(nibName: Self.nibName, bundle: bundle)
    }

    func setupFromNib() {
        guard let view = Self.nib.instantiate(withOwner: self, options: nil).first as? UIView else { fatalError("Error loading \(self) from nib") }
        addSubview(view)
        view.translatesAutoresizingMaskIntoConstraints = false
        view.leadingAnchor.constraint(equalTo: self.safeAreaLayoutGuide.leadingAnchor, constant: 0).isActive = true
        view.topAnchor.constraint(equalTo: self.safeAreaLayoutGuide.topAnchor, constant: 0).isActive = true
        view.trailingAnchor.constraint(equalTo: self.safeAreaLayoutGuide.trailingAnchor, constant: 0).isActive = true
        view.bottomAnchor.constraint(equalTo: self.safeAreaLayoutGuide.bottomAnchor, constant: 0).isActive = true
    }
}

Ed ecco un esempio di MyCustomClassciò che implementa il protocollo (con il nome del file .xib MyCustomClass.xib):

@IBDesignable
class MyCustomClass: UIView, NibLoadable {

    @IBOutlet weak var myLabel: UILabel!

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupFromNib()
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupFromNib()
    }

}

NOTA: se ti manca Gotcha e imposti il classvalore all'interno del tuo file .xib come classe personalizzata, non verrà disegnato nello storyboard e visualizzerai un EXC_BAD_ACCESSerrore quando esegui l'app perché si blocca in un ciclo infinito di cercando di inizializzare la classe dal pennino usando il init?(coder aDecoder: NSCoder)metodo che quindi chiama Self.nib.instantiatee chiama di initnuovo.


2
Ecco un altro ottimo approccio, ma ritengo che quello sopra sia ancora migliore: medium.com/zenchef-tech-and-product/…
Ben Patch

4
L'approccio sopra citato funziona perfettamente e applica l'anteprima dal vivo direttamente nello storyboard. È assolutamente utile e fantastico, grande!
Igor Leonovich,

1
Cordiali saluti: questa soluzione, utilizzando la definizione di vincolo in setupFromNib(), sembra risolvere alcuni strani problemi di layout automatico con celle di visualizzazione tabella con ridimensionamento automatico contenenti viste create da XIB.
Gary

1
Di gran lunga la migliore soluzione! Adoro la @IBDesignablecompatibilità. Non riesco a credere perché Xcode o UIKit non forniscano qualcosa di simile come predefinito quando si aggiunge un file UIView.
fl034,

1
non riesco a farlo funzionare. Ogni volta che imposto File Owner all'interno del mio file .xib, imposta ANCHE classe personalizzata.
Drewster,

32

Supponendo di aver creato un xib che si desidera utilizzare:

1) Crea una sottoclasse personalizzata di UIView (puoi andare su File -> Nuovo -> File ... -> Cocoa Touch Class. Assicurati che "Sottoclasse di:" sia "UIView").

2) Aggiungi una vista basata su xib come sottoview a questa vista durante l'inizializzazione.

In Obj-C

-(id)initWithCoder:(NSCoder *)aDecoder{
    if (self = [super initWithCoder:aDecoder]) {
        UIView *xibView = [[[NSBundle mainBundle] loadNibNamed:@"YourXIBFilename"
                                                              owner:self
                                                            options:nil] objectAtIndex:0];
        xibView.frame = self.bounds;
        xibView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
        [self addSubview: xibView];
    }
    return self;
}

In Swift 2

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    let xibView = NSBundle.mainBundle().loadNibNamed("YourXIBFilename", owner: self, options: nil)[0] as! UIView
    xibView.frame = self.bounds
    xibView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
    self.addSubview(xibView)
}

In Swift 3

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    let xibView = Bundle.main.loadNibNamed("YourXIBFilename", owner: self, options: nil)!.first as! UIView
    xibView.frame = self.bounds
    xibView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    self.addSubview(xibView)
}

3) Ovunque tu voglia usarlo nello storyboard, aggiungi una UIView come faresti normalmente, seleziona la nuova vista aggiunta, vai a Identity Inspector (la terza icona in alto a destra che assomiglia a un rettangolo con linee al suo interno), e inserisci il nome della sottoclasse come "Classe" in "Classe personalizzata".


xibView.frame = self.frame;dovrebbe essere xibView.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);, altrimenti xibView avrà un offset quando la vista viene aggiunta allo storyboard.
BabyPanda

in ritardo alla festa, ma sembra che l'abbia cambiato in xibView.frame = self.bounds, che è un frame senza offset
Heavy_Bullets

20
Risultati in un arresto anomalo a causa della ricorsione infinita. Il caricamento del pennino crea un'altra istanza della sottoclasse.
David

2
La classe della vista xib non dovrebbe essere la stessa di questa nuova sottoclasse. Se xib è MyClass, puoi creare questa nuova classe MyClassContainer.
user1021430,

la soluzione sopra cadrà in infinita ricorsione.
JBarros35,

27

Ho sempre trovato insoddisfacente la soluzione "aggiungi come sottoview", visto che si avvita con (1) autolayout, (2) @IBInspectablee (3) outlet. Invece, lascia che ti presenti la magia di awakeAfter:, unNSObject metodo.

awakeAfterconsente di scambiare l'oggetto effettivamente svegliato da un NIB / Storyboard con un oggetto completamente diverso. Che scopo viene poi messo attraverso il processo di idratazione, ha awakeFromNibchiamato su di esso, viene aggiunto come vista, etc.

Possiamo usarlo in una sottoclasse di "ritagli di cartone" secondo la nostra visione, il cui unico scopo sarà caricare la vista dal NIB e restituirla per l'uso nello Storyboard. La sottoclasse incorporabile viene quindi specificata nella finestra di ispezione delle identità della vista Storyboard, piuttosto che nella classe originale. In realtà non deve essere una sottoclasse affinché funzioni, ma renderla una sottoclasse è ciò che consente a IB di vedere le proprietà IBInspectable / IBOutlet.

Questa piastra aggiuntiva potrebbe sembrare non ottimale - e in un certo senso lo è, perché idealmente UIStoryboarddovrebbe gestirla senza problemi - ma ha il vantaggio di lasciare completamente il NIB originale e la UIViewsottoclasse. Il ruolo che svolge è fondamentalmente quello di un adattatore o di una classe bridge ed è perfettamente valido, dal punto di vista del design, come classe aggiuntiva, anche se è deplorevole. D'altro canto, se preferisci essere parsimonioso con le tue classi, la soluzione di @ BenPatch funziona implementando un protocollo con alcune altre modifiche minori. La domanda su quale soluzione sia migliore si riduce a una questione di stile del programmatore: se si preferisce la composizione degli oggetti o l'ereditarietà multipla.

Nota: la classe impostata nella vista nel file NIB rimane la stessa. La sottoclasse incorporabile viene utilizzata solo nello storyboard. La sottoclasse non può essere utilizzata per creare un'istanza della vista nel codice, quindi non dovrebbe avere alcuna logica aggiuntiva. Dovrebbe contenere solo il awakeAftergancio.

class MyCustomEmbeddableView: MyCustomView {
  override func awakeAfter(using aDecoder: NSCoder) -> Any? {
    return (UIView.instantiateViewFromNib("MyCustomView") as MyCustomView?)! as Any
  }
}

⚠️ L'unico svantaggio significativo qui è che se si definiscono vincoli di larghezza, altezza o proporzioni nello storyboard che non si riferiscono a un'altra vista, devono essere copiati manualmente. I vincoli che riguardano due viste sono installati sull'antenato comune più vicino e le viste vengono risvegliate dallo storyboard dall'interno verso l'esterno, quindi quando questi vincoli vengono idratati sulla superview lo scambio è già avvenuto. I vincoli che riguardano solo la vista in questione vengono installati direttamente su quella vista e vengono quindi lanciati quando si verifica lo scambio a meno che non vengano copiati.

Si noti che ciò che sta accadendo qui è che i vincoli installati nella vista nello storyboard vengono copiati nella vista appena istanziata , che potrebbe già avere vincoli propri, definiti nel suo file pennino. Quelli non sono interessati.

class MyCustomEmbeddableView: MyCustomView {
  override func awakeAfter(using aDecoder: NSCoder) -> Any? {
    let newView = (UIView.instantiateViewFromNib("MyCustomView") as MyCustomView?)!

    for constraint in constraints {
      if constraint.secondItem != nil {
        newView.addConstraint(NSLayoutConstraint(item: newView, attribute: constraint.firstAttribute, relatedBy: constraint.relation, toItem: newView, attribute: constraint.secondAttribute, multiplier: constraint.multiplier, constant: constraint.constant))
      } else {
        newView.addConstraint(NSLayoutConstraint(item: newView, attribute: constraint.firstAttribute, relatedBy: constraint.relation, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: constraint.constant))
      }
    }

    return newView as Any
  }
}  

instantiateViewFromNibè un'estensione sicura per i tipi di UIView. Tutto ciò che fa è passare in rassegna gli oggetti del NIB fino a quando non trova quello che corrisponde al tipo. Si noti che il tipo generico è il valore restituito , quindi il tipo deve essere specificato nel sito della chiamata.

extension UIView {
  public class func instantiateViewFromNib<T>(_ nibName: String, inBundle bundle: Bundle = Bundle.main) -> T? {
    if let objects = bundle.loadNibNamed(nibName, owner: nil) {
      for object in objects {
        if let object = object as? T {
          return object
        }
      }
    }

    return nil
  }
}

Questo è strabiliante. Se non sbaglio, però, funziona solo "sullo storyboard" - se provi a creare una tale classe di codice in fase di esecuzione, non penso che funzioni. Credo.
Fattie,

La sottoclasse dovrebbe funzionare sia nel codice che nella classe originale a tutti gli effetti. Se si desidera caricare la vista da un pennino nel codice, è sufficiente creare un'istanza direttamente utilizzando la stessa tecnica. Tutto ciò che fa la sottoclasse è prendere il codice per creare un'istanza della vista da un pennino e metterlo in un gancio per l'utilizzo dello storyboard.
Christopher Swasey,

In realtà mi sbagliavo: avrebbe funzionato altrettanto bene se avessi potuto istanziarlo, ma non puoi, perché la vista nel NIB avrà la superclasse come tipo, quindi instantiateViewFromNibnon restituirà nulla. Non è un grosso problema in entrambi i casi IMO, la sottoclasse è solo un espediente da agganciare allo storyboard, tutto il codice dovrebbe essere nella classe originale.
Christopher Swasey,

1
Grande! Una cosa mi ha fatto scattare perché ho poca esperienza con xibs (ho sempre lavorato con storyboard e approcci programmatici), lasciandolo qui nel caso in cui aiuti qualcuno: nel file .xib, devi selezionare la vista di livello superiore e impostare il suo tipo di classe a MyCustomView. Nel mio xib la barra laterale interna sinistra mancava di default; per accenderlo, c'è un pulsante accanto al controllo dei tratti "Visualizza come: iPhone 7" vicino al lato inferiore / sinistro.
xaphod

5
Frena i vincoli quando viene sostituito da un altro oggetto. :(
invoodoo,

6

La migliore soluzione attualmente è semplicemente usare un controller di visualizzazione personalizzato con la sua vista definita in un xib ed eliminare semplicemente la proprietà "view" che Xcode crea all'interno dello storyboard quando si aggiunge il controller di visualizzazione (non dimenticare di impostare il nome di la classe personalizzata però).

Questo farà in modo che il runtime cerchi automaticamente lo xib e lo carichi. Puoi usare questo trucco per qualsiasi tipo di vista contenitore o vista contenuto.


5

Penso alternativeall'utilizzo XIB viewsda utilizzare View Controller in storyboard separato .

Poi, nel storyboard principale luogo di utilizzo visualizzazione personalizzata container viewcon Embed Seguee hanno StoryboardReferencea questo controller di visualizzazione personalizzata che guarda dovrebbe essere inserito all'interno di altra vista in storyboard principale.

Quindi possiamo impostare la delega e la comunicazione tra questo ViewController integrato e il controller della vista principale attraverso la preparazione per seguire . Questo approccio è diverso rispetto alla visualizzazione di UIView, ma molto più semplice ed efficiente (dal punto di vista della programmazione) può essere utilizzato per raggiungere lo stesso obiettivo, ovvero avere una vista personalizzata riutilizzabile che è visibile nello storyboard principale

Il vantaggio aggiuntivo è che puoi implementare la tua logica nella classe CustomViewController e impostare tutta la delega e la preparazione della vista senza creare classi di controller separate (più difficili da trovare nel progetto) e senza inserire il codice della caldaia nel UIViewController principale utilizzando Component. Penso che questo vada bene per i componenti riutilizzabili ex. Componente di Music Player (simile a un widget) integrabile in altre viste.


In effetti, purtroppo, una soluzione molto più semplice rispetto all'utilizzo della visualizzazione personalizzata xib :(
Wilson,

1
dopo essere andato in cerchio con la catena di creazione del ciclo di vita xib di Apple su UIView personalizzata, questo è il modo in cui ho finito.
LightningStryk,

Nel caso in cui desideri aggiungere dinamicamente la vista personalizzata, dobbiamo comunque scegliere un controller di vista separato (preferibilmente XIB)
Satyam,

5

Sebbene le migliori risposte più popolari funzionino bene, sono concettualmente sbagliate. Usano tutti File's ownercome connessione tra punti vendita della classe e componenti dell'interfaccia utente. File's ownerdovrebbe essere usato solo per oggetti di livello superiore non UIViews. Consulta il documento per sviluppatori Apple . Avere UIView come File's ownercausa di queste conseguenze indesiderabili.

  1. Sei costretto a usare contentViewdove dovresti usareself . Non è solo brutto, ma anche strutturalmente sbagliato perché la vista intermedia impedisce alla struttura dei dati di comunicare la sua struttura dell'interfaccia utente. È come il contrario dell'interfaccia utente dichiarativa.
  2. Puoi avere un solo UIView per Xib. Un Xib dovrebbe avere più UIVview.

C'è un modo elegante per farlo senza usare File's owner. Si prega di controllare questo post sul blog . Spiega come farlo nel modo giusto.


non importa per niente non hai spiegato perché è male. Non vedo perché. Non ci sono effetti collaterali.
JBarros35

1

Ecco la risposta che hai sempre desiderato. Puoi semplicemente creare la tua CustomViewclasse, avere l'istanza principale in un xib con tutte le visualizzazioni secondarie e punti vendita. Quindi puoi applicare quella classe a tutte le istanze nei tuoi storyboard o altri xib.

Non c'è bisogno di giocherellare con il proprietario del file, o collegare le prese a un proxy o modificare xib in un modo particolare, o aggiungere un'istanza della vista personalizzata come sottoview di se stesso.

Basta fare questo:

  1. Importa il framework BFWControls
  2. Cambia la tua superclasse da UIViewa NibView(o da UITableViewCella NibTableViewCell)

Questo è tutto!

Funziona anche con IBDesignable per fare riferimento alla vista personalizzata (comprese le visualizzazioni secondarie di xib) in fase di progettazione nello storyboard.

Puoi leggere di più qui: https://medium.com/build-an-app-like-lego/embed-a-xib-in-a-storyboard-953edf274155

E puoi ottenere il framework open source BFWControls qui: https://github.com/BareFeetWare/BFWControls

Ed ecco un semplice estratto del NibReplaceablecodice che lo guida, nel caso tu sia curioso:
 https://gist.github.com/barefeettom/f48f6569100415e0ef1fd530ca39f5b4

Tom 👣


Ottima soluzione, grazie!
Avee,

Non voglio installare un framework quando dovrebbe essere fornito in modo nativo.
JBarros35,

0

Questa soluzione può essere utilizzata anche se la tua classe non ha lo stesso nome di XIB. Ad esempio, se si dispone di un controller di classe controllerA con vista di base che ha un nome XIB controllerA.xib e questo è stato sottoposto a una sottoclasse con controllerB e si desidera creare un'istanza di controllerB in uno storyboard, è possibile:

  • crea il controller di visualizzazione nello storyboard
  • imposta la classe del controller su controllerB
  • elimina la vista del controllerB nello storyboard
  • sovrascrivere la vista di carico nel controllerA per:

*

- (void) loadView    
{
        //according to the documentation, if a nibName was passed in initWithNibName or
        //this controller was created from a storyboard (and the controller has a view), then nibname will be set
        //else it will be nil
        if (self.nibName)
        {
            //a nib was specified, respect that
            [super loadView];
        }
        else
        {
            //if no nib name, first try a nib which would have the same name as the class
            //if that fails, force to load from the base class nib
            //this is convenient for including a subclass of this controller
            //in a storyboard
            NSString *className = NSStringFromClass([self class]);
            NSString *pathToNIB = [[NSBundle bundleForClass:[self class]] pathForResource: className ofType:@"nib"];
            UINib *nib ;
            if (pathToNIB)
            {
                nib = [UINib nibWithNibName: className bundle: [NSBundle bundleForClass:[self class]]];
            }
            else
            {
                //force to load from nib so that all subclass will have the correct xib
                //this is convenient for including a subclass
                //in a storyboard
                nib = [UINib nibWithNibName: @"baseControllerXIB" bundle:[NSBundle bundleForClass:[self class]]];
            }

            self.view = [[nib instantiateWithOwner:self options:nil] objectAtIndex:0];
       }
}

0

Soluzione per Objective-C secondo i passaggi descritti nella risposta di Ben Patch .

Usa l'estensione per UIView:

@implementation UIView (NibLoadable)

- (UIView*)loadFromNib
{
    UIView *xibView = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:self options:nil] firstObject];
    xibView.translatesAutoresizingMaskIntoConstraints = NO;
    [self addSubview:xibView];
    [xibView.topAnchor constraintEqualToAnchor:self.topAnchor].active = YES;
    [xibView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor].active = YES;
    [xibView.leftAnchor constraintEqualToAnchor:self.leftAnchor].active = YES;
    [xibView.rightAnchor constraintEqualToAnchor:self.rightAnchor].active = YES;
    return xibView;
}

@end

Creare file MyView.h, MyView.me MyView.xib.

Prima prepara il tuo MyView.xibcome dice la risposta di Ben Patch, quindi imposta la classe MyViewper il proprietario di File anziché la vista principale all'interno di questo XIB.

MyView.h:

#import <UIKit/UIKit.h>

IB_DESIGNABLE @interface MyView : UIView

@property (nonatomic, weak) IBOutlet UIView* someSubview;

@end

MyView.m:

#import "MyView.h"
#import "UIView+NibLoadable.h"

@implementation MyView

#pragma mark - Initializers

- (id)init
{
    self = [super init];
    if (self) {
        [self loadFromNib];
        [self internalInit];
    }
    return self;
}

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self loadFromNib];
        [self internalInit];
    }
    return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
        [self loadFromNib];
    }
    return self;
}

- (void)awakeFromNib
{
    [super awakeFromNib];
    [self internalInit];
}

- (void)internalInit
{
    // Custom initialization.
}

@end

E in seguito basta creare la vista in modo programmatico:

MyView* view = [[MyView alloc] init];

Avvertimento! L'anteprima di questa vista non verrà mostrata nello Storyboard se si utilizza l'estensione WatchKit a causa di questo errore in Xcode> = 9.2: https://forums.developer.apple.com/thread/95616


Avrebbe dovuto fornire la versione Swift. Pochissimi potrebbero usare ObjC ancora in questo momento
Satyam,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.