Compatibile con Xcode 8

NavigationController e Segue. Abilitare lo spostamento tra Controller

ENTRA NEL NOSTRO GRUPPO FACEBOOK

×

Corso creare applicazioni per iOS con il linguaggio Swift

A tutti sarà capitato di fare da passaparola tra due persone. Il primo attore ti affida un messaggio, tu lo conservi e lo porti a destinazione. Il secondo attore elabora il messaggio e può decidere se darti una risposta da consegnare oppure no. Se volessimo schematizzare il procedimento, i personaggi in gioco sono 3 (anche se vedrai [...]

Torna a: Corso creare applicazioni per iOS con il linguaggio Swift > Applicazioni Multi Interfacce
  • Alessandro

    Ciao Peppe, ho provato ad embeddare Il Navigation Controller ad una Table View Controller. Ho notato però che non mi fa aggiungere i Bar Button Item…volevo aggiungere banalmente un bottone “+” per aprire una modale di inserimento dati..come mai non riesco? :-( Nessun problema invece con un View Controller normale..

    • Ciao Alessandro,
      Prima di aggiungere il Bar Button Item, aggiungi il Navigation Item. Questo attiverà il posizionamento degli elementi sulla barra (lo spiego nel prossimo tutorial che spero di rilasciare stasera o domani).
      Fammi sapere ;)

      • Alessandro

        Grazie della risposta Peppe. Ce l’ho già il Navigation Item.. :-(
        Dai a questo punto se lo spieghi nella prossima lezione attendo..ad ogni modo mi fa strano..ho usato direttamente l’oggetto grafico Navigation Controller che si è portato dietro già un root table view controller e infatti nel Document Outline c’è la navigation item, ho anche cambiato il titolo..

      • Alessandro

        Come non detto…chiuso e riparto Xcode e ora funziona….. :-( mah!

  • Francesco

    Ciao,

    ho fatto delle prove tutt ok
    ma mi succede questo è vorrei capire il perchè:

    ho creato 3 VC e NC A > B > C tutto ok tramite in navigator Bar

    nella VC C ho inserito per provare il metodo che torna indietro di 1 e quello che porta diciamo direttamente alla homepage, tutto funziona dnella modalità Show ma se provo a cambiare il tipo di transazione io ho provato present Modally i bottoni non funzionano più. Ovviamente come spiegato la Navigation bar sparisce, forse i 2 metodi sono legati alla Sua presenza?.

    • Ciao Francesco,
      Ad ogni modo, tutti i segue che sono sono Show, tolgono la relazione con il Navigation Controller. Dai uno sguardo alla prossima lezione :P

  • Michele

    Ciao Peppe, una curiosità.

    Abbiamo visto ad inizio lezione come impostare il Navigation controller come “is inizial view controller” e collegare il Navigation Controller al primo ViewController.

    Noto che in alcune applicazioni però la view iniziale può cambiare.
    Es. prima ti faccio una presentazione del prodotto tipo dropbox, poi arrivo alla login.
    Ma se la presentazione te l’ho già fatta vedere (e questo immagino tu possa registrarlo da qualche parte sul device come info) vai alla login. Poi, se l’utente è in verità già loggato passa alla schermata principale dell’app. Questa logica la ritrovo in tante app e mi da l’impressione di cambiare in runtime il puntamento tra il navigation controller ed il primo view controller da visualizzare. Puoi spiegarmi (ovviamente in linea di principio) come si mette questa esperienza utente rispetto alle cose apprese in questa lezione? O è meglio pazientare e leggere qualche altra lezione? :-)

    Grazie sempre,
    Michele

    • Ciao Michele,

      Ottima domanda!

      Quel sistema può essere realizzato con un semplice salvataggio in memoria di un valore booleano che passa a true quando l’utente apre per la prima volta l’app (si fa con l’NSUserDefault, lo vedremo una volta finito con le tabelle).

      Il sistema è abbastanza semplice:

      Prevede un NavController ed un VC iniziale classico, come quelli che abbiamo realizzato, con una Page View Controller (un VC dove si può muovere a destra e sinistra, con la gesture, per mostrare diverse pagine – il classico tutorial iniziale). Dopo il VC con il page view controller c’è il VC con il login.

      Se l’utente ha già visto il tutorial, il NavigationController passa direttamente al secondo VC dell’array che sarebbe quello di login.

      Queste operazioni, generalmente, vengono eseguite all’interno del metodo didFinishLaunchingWithOptions (nell’AppDelegate).

      Quindi se vuoi già provare qualcosa ti ho scritto cosa andare a cercare :P
      Mentre noi lo realizzeremo più avanti!

      Grazie a te,
      Giuseppe

  • nickbonny

    Ciao peppe, ti stufo ancora con delle domande..

    Ho un po’ la testa dura, ma non riesce ad entrarmi bene in testa il funzionamento del self.

    Cioè, quando vado a fare:

    self.performSegueWithIdentifier()

    oppure

    self.navigationController?.popViewControllerAnimated(true)

    Perché mi serve mettere il self?

    • ciao nickBonny,
      self si usa per indicare una proprietà’ della istanza corrente della classe che stai usando. faccio un esempio:
      class MiaClasse {
      var a: Int // proprieta’ della classe
      var b: Int // proprieta’ della classe
      init(a: Int, b: Int) { // inizializzatore che accetta 2 parametri nominati come le proprieta’ self.a = a // self.a indica la ‘vera’ proprieta’ della classe, mentre solo a indica il parametro passato alla funzione init self.b = b // stessa cosa
      }
      func stampaA() {
      print(self.a) // anche qui vogliamo, da dentro la classe, accedere una sua proprieta’ }
      func stampaB() {
      print(self.b) // anche qui vogliamo, da dentro la classe, accedere una sua proprieta’ }
      func stampa() {
      self.stampaA() // lo stesso vale per i metodi interni alla classe self.stampaB()
      performSegueWithIdentifier() // stesso come succede nel tuo codice
      }
      func performSegueWithIdentifier() {
      //…
      }
      }
      var pino = MiaClasse(a:1, b:2)
      pino.stampa()

      quindi, quando scrivi dentro ad una classe come viewController e ti riferisci ad un metodo o proprieta’ interni, usi self per specificare il metodo o la propieta’ di ‘questa’ stessa istanza, se stessa appunto. UIViewController ha un metodo chiamato
      func performSegueWithIdentifier() {…}
      ovviamente noi scriviamo codice dentro i metodi della classe, quindi usiamo il self, esattamente come nella classe di prova che ti ho presentato, la classe viene eseguita esternamente, diciamo che c’e’ un pezzo di programma ‘che non vediamo’ che e’ scritto cosi’: viewController.viewDidLoad()
      che fa partire tutta la nostra app, equivalente al pino.stampa() dell’esempio, da “li’ fuori” i self nn si usano, ma ci si riferisce direttamente a metodi e proprieta’ interne all’istanza: pino.a = 5.

      spero di averti aiutato nella comprensione

  • Michele

    Frustrazione…
    ciao Peppe, sto costruendo piano piano una mia app.
    Ho 3 VC, i segue fra i primi due funzionano bene. Dopo aver lavorato un po’ sul codice dei primi due (integrazione con Parse e Facebook, login e setting dell’account) ho aggiunto un terzo VC a cui voglio rimandare in caso di problemi di network o in caso in cui ci siano altri problemi di try. Ok qui sto veramente “uscendo pazzo”.

    Ho creato il VC ErrorVC
    Ho creato una nuova classe ErrorViewController: UIViewController
    Ho assegnato la classe al nuovo oggetto VC nella sezione Custom class
    Ho premuto ctrl e fatto drag end drop dal VCSettings al VCError
    Ho dato un identifier al segue “settings2error”
    Ho impostato il segue con kind: show (ed ho provato con show detail)
    Ho inserito una cavolo di riga di codice dentro il VCSettings:

    override func viewDidLoad() {
    super.viewDidLoad()
    self.performSegueWithIdentifier(“settings2error”, sender: nil)

    Mi aspetto che caricata la view VCSettings passi immediatamente alla view VCError… ma non fa un tubo.
    Non mi da errore, ma mi ignora la riga di codice…
    ed esegue il resto del codice sotto.

    Hai una qualche idea di cosa cavolo possa essere?
    Grazie un milione,

    Michele

    • Michele

      Ciao Peppe,
      cercando su stack overflow ho trovato la seguente soluzione…

      dispatch_async(dispatch_get_main_queue()) {
      self.performSegueWithIdentifier(“settings2error”, sender: nil)
      }

      Da quel poco che ho capito non eseguivo il comando nella coda del thread principale.
      Ok, sapresti dirmi come faccio senza quelle righe sconosciute ad eseguire il segue come visto nella lezione ?!

      • Michele

        E il mistero si infittisce…
        Nonostante il simulatore effettivamente cambi View nella VCError… viene ugualmente eseguito parte del codice (o tutto) del corrente viewDidLoad.

        override func viewDidLoad() {
        super.viewDidLoad()
        dispatch_async(dispatch_get_main_queue()) {
        self.performSegueWithIdentifier(“settings2error”, sender: nil)
        }
        //Perchè lo stampi??
        print(“Non mi stampare…”)
        }

        Ok prima quindi avevo 1 domanda, adesso ne ho due!
        1)Perché il performSegue “scivola” fuori dal main thread??
        2)Perché continua ad eseguirmi il codice contenuto nel ViewDidLoad dopo il segue invece di passare subito il controllo alla nuova View?

        Thx!

        • Ciao Michele,

          Partiamo da presupposto che, generalmente, i messaggi d’errore vengono gestiti con le AlertView o comunque finestre che appaiono dentro il ViewController in cui nasce l’errore (è sconsigliato spostare la gestione di un errore in un altro VC).

          Invece, provare a fare un segue dal viewDidLoad è un’operazione alquanto inusuale dato che il viewDidLoad viene caricato prima dell’apparizione, nello schermo, del VC in questione. Quindi tu stai forzando il passaggio ad un altro VC prima ancora che il VC di partenza venga renderizzato.

          Se invece vuoi risolvere il tuo problema puoi utilizzare il sistema che ho spiegato in questo thread che dovrebbe fare al caso tuo -> http://www.xcoding.it/community/topic/problema-alterview/

          Ma, come ti dicevo, l’approccio al problema è un po’ sbagliato. Ti consiglio di aggiungere le Alert View o altri sistemi di notifica degli errori.

          Fammi sapere ;)

          • Michele

            Ciao Peppe,
            alla fine ho fatto così:
            nell’appdegate imposto un controllo per vedere se l’utente è loggato o meno ed imposto il rootViewController di conseguenza. Ho scritto così e funziona (anche se il mio codice è poco elegante…)

            if currentUser != nil && currentUser!.objectForKey(“emailVerified”)?.boolValue == true
            {
            self.window!.rootViewController = self.window!.rootViewController?.storyboard?.instantiateViewControllerWithIdentifier(“Settings”)
            } else {
            // Show the signup & login screen
            self.window!.rootViewController = self.window!.rootViewController?.storyboard?.instantiateViewControllerWithIdentifier(“Login”)
            }

            Ho creato un file aggiuntivo .swift che mi fa da libreria dove metto tutte le funzioni che richiamo usualmente nel vari ViewController. Dentro questo file ho aggiunto la public class Reachability.

            All’interno di ogni ViewController

            override func viewWillAppear(animated: Bool) {
            super.viewWillAppear(animated);
            //Check network connection
            if Reachability.isConnectedToNetwork() == true {
            print(“Internet connection OK”)
            } else {
            print(“Internet connection FAILED”)
            dispatch_async(dispatch_get_main_queue()) {
            self.performSegueWithIdentifier(“login2error”, sender: nil)
            }
            }
            }

            All’interno del VC Error ho un pulsante Retry. Se viene premuto richiama la classe Reachability. Se manca la connessione non fa nulla e l’utente resta nella viewErrore senza poter uscire (cosa che invece una alert view non fa e poi mi toccherebbe prevenire tutti i danni che l’utente potrebbe fare andando sui vari controlli, certo una buona programmazione con try e catch risolverebbe,ma non sono ancora così bravo… e paziente!).
            Se invece il controllo di raggiungibilità restituisce true allora dismetto la finestra modal con self.dismissViewControllerAnimated(true, completion: self.fineEsecuzione) come dalla tua guida.

            Anche se poco ortodosso, questo è il risultato!
            A presto e grazie,
            Michele

            • Perfetto Michele e grazie per aver condiviso.
              Per il resto va benissimo anche così ;)

  • Alain Desitter

    Ciao Peppe, grazie per i consigli, la mia app sta prendendo forma, soprattutto grazie a queste dettagliate lezioni.
    Mi sono impastato sull’inserimento di un terzo VC.
    La mia app ha:
    Navigation Controller
    Primo VC che è una slide contenente il logo aziendale ed i colori aziendali
    Secondo VC La schermata di login.

    fin qui tutto bene, grazie alla navigazione bar di default del navigazione controller e le ibaction mi sposto senza problemi.

    Ora ho aggiunto un terzo VC che sarà dedicato ad un elenco dei prodotti, ho creato il VC, ho creato la nuova classe, ho creato il segue dalla 2 alla 3 con il suo identifica … provo a mettere un item navigator bar nella barra di navigazione del seco VC così da farlo passare al terzo ma l’oggetto non si crea, come faccio a fare lo stesso passaggio che ho dal VC1 al VC2 funzionante con il VC2 al VC3?

    • Ciao Alain, sono davvero contento che la tua prima applicazione stia prendendo forma grazie al corso ;)

      Da quello che ho capito il VC3 non ha la navigation bar. Il problema potrebbe dipendere dal fatto che hai utilizzato un segue diverso dal tipo Show che farebbe ereditare la Top Bar dal Navigation Controller.

      Ad ogni modo se vuoi avere il VC2 come punto di partenza per tutti gli altri e non come conseguenza del VC1, metti al VC2 il navigation controller e toglilo dal VC1.

      Se il VC1 è solo una presentazione dei loghi e cose di questo genere, puoi tranquillamente scorporarlo dalla navigazione principale che è quella che avviene tra VC2 e VC3.

      Rimango in attesa di delucidazioni,
      Giuseppe

      • Alain Desitter

        Ciao Beppe,

        purtroppo no, il problema è diverso, su tutti i VC vedo la
        navigation bar, il problema è che riesco a creare il tasto avanti solo nella
        barra di navigazione del VC1 con il suo collegamento al segue verso il VC2.

        Nel VC2 non mi fa creare il bottone avanti così da collegarlo
        al VC3 e cosi via con il VC4

        Quando prendo l’oggetto Item Navigation Bar e lo trascino, l’icona
        non mi diventa il +verde che mi fa posizionare l’oggetto, se rilascio scompare
        sotto.

        Sicuramente sbaglio qualche cosa ma non capisco cosa

        • Ciao Alain,
          Devi trascinare un semplice Bar Buttom Item all’interno della Navigation perché già quest’ultima è presente (anche se non modificabile).

          Fammi sapere! In caso, se ti va mandami il progetto o ti faccio io un esempio con un mini video

          Giuseppe

          • Alain Desitter

            ok, forse ho capito l’errore, ho rifatto il progetto con dei tasti creati da me e riesco a navigare fra le 5 slide, se attivo la Navigation Bar riesco a passare solo dal VC1 al VC2.

            Ero convinto di dover creare l’oggetto Button all’interno di ogni Navigation Bar di ogni VC ma ho visto che l’oggetto Navigation Item mi compare solo nel VC1.

            Quindi nasce un’altra domanda: ma la barra di navigazione del Navigator Controller deve essere gestita solo da codice?

            • No Alain, negli altri VC che sono collegati con il segue di tipo Show (quindi hanno già una navigation bar) per inserire il titolo o altri bottoni, devi inserire una navigation item (e non la navigation bar perché già è presente)

              Se invece il ViewController non è collegato ad un Navigation Controller (direttamente o indirettamente da altri VC con push show) devi aggiungere la navigation bar manualmente.

              Ad ogni modo, se vuoi mi puoi mandare il progetto così lo guardo e ti dico di preciso come fare

              Buona Programmazione,
              Giuseppe

            • Alain Desitter

              ok, finisco di buttare giù tutta la logica con i tasti e poi te lo mando, grazie mille per il supporto

            • Perfetto Alain,
              In caso fammi sapere!

  • Alessandro Capuano

    Ciao Peppe,
    ancora complimenti per il corso e grazie per l’impegno che ci metti!

    Il mio problema riguarda i metodi popToRootViewControllerAnimated e popViewControllerAnimated del navigation controller:
    se provo ad utilizzare il metodo con la stringa
    self.navigationController?.popToRootViewControllerAnimated(true)
    ottengo l’errore:
    Indice.swift:32:36: ‘popToRootViewControllerAnimated’ has been renamed to ‘popToRootViewController(animated:)’

    se utilizzo la sintassi proposta e quindi modifico la stringa in:
    self.navigationController?.popToRootViewController(animated: true)
    ottengo la segnalazione “gialla”:
    Indice.swift:32:36: Expression of type ‘[UIViewController]?’ is unused

    Stesso identico problema con l’altro metodo.

    • Ciao Alessandro, il problema deriva dalla nuova versione di Xcode 8 e dalla sintassi di swift 3.0.
      Mi faresti vedere, per favore, uno screen del codice e l’errore?

  • Ciao Peppe,
    anche io ho lo stesso problema di Alessandro con il metodo:
    self.navigationController?.popViewController(animated: true)

    mi appare sempre l’attenzione gialla…
    da quando ho aggiornato a Xcode 8
    Risolvo la faccenda dandogli il l’ Unwrap con il marcatore ! al posto del ? e non mi da più l’errore.
    E’ corretto?

    • Ciao Luca, si è corretto. Adesso non è più possibile richiamare il pop in maniera opzionale
      Giuseppe Sapienza
      Founder | xCoding.it – Sviluppa, Crea e Codifica i tuoi Sogni

Start typing and press Enter to search