8

Ho due UIPickerViews differenti nella mia vista. Funzionano alla grande quando imposto il data source e il delegato alla vista in cui sono ospitati tramite lo storyboard, ma quando provo a farlo tramite codice come descritto di seguito, non funziona.UIPickerView con origine dati "esterna" e delegato in Swift

Entrambi i raccoglitori devono avere dati diversi da visualizzare (e forse anche comportamenti diversi per il delegato). Quindi mi piacerebbe collegarli a fonti di dati differenti a livello di programmazione.

Ho provato a creare la mia classe implementando i protocolli UIPickerViewDataSource- e UIPickerViewDelegate e collegando oggetti di quella classe a PickerViews, ma non funziona. Viene generata un'eccezione in fase di esecuzione terminating with uncaught exception of type NSException affermando questo:

2015-01-09 17:50:05.333 Pet Stats[4953:244338] -[NSConcreteMapTable numberOfComponentsInPickerView:]: unrecognized selector sent to instance 0x7b4616d0 
2015-01-09 17:50:05.338 Pet Stats[4953:244338] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSConcreteMapTable numberOfComponentsInPickerView:]: unrecognized selector sent to instance 0x7b4616d0' 

Come posso ottenere questo lavoro? Cosa mi sono perso? Qui è il mio codice:

WeightWheelController.swift

import UIKit 

class WeightWheelController: NSObject, UIPickerViewDelegate, UIPickerViewDataSource { 
    let ElementCount: Int! 

    init(pickerInterval: Int) { 
     ElementCount = pickerInterval 
    } 

    func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int { 
     return 1 
    } 

    func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { 
     return ElementCount 
    } 

    func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! { 
     return String(row + 1) 
    } 

    func pickerView(pickerView: UIPickerView!, didSelectRow row: Int, inComponent component: Int) 
    { 
     println("External Controller:" + String(row + 1)) 
    } 
} 

WeightWheelInputViewController.swift

import UIKit 

class WeightWheelInputViewController: UIViewController { 
    @IBOutlet weak var picker1: UIPickerView!   
    @IBOutlet weak var picker2: UIPickerView! 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     //picker attached to c1 should show number from 1 to 150 
     let c1 = WeightWheelController(pickerInterval: 150) 

     //picker attached to c1 should show number from 1 to 10 
     let c2 = WeightWheelController(pickerInterval: 10) 

     picker1.dataSource = c1 
     picker1.delegate = c1 

     picker2.dataSource = c2 
     picker2.delegate = c2 
    } 

    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
    } 
} 

breve aggiornamento:

In questa domanda ho scoperto che è possibile utilizzare tag diversi per diverse visualizzazioni di picker. Questa sarebbe un'opzione; ancora, non mi piace. Vorrei piuttosto seguire un approccio MVC e connettere controller diversi a ciascun selezionatore. Non è possibile in alcun modo?

risposta

13

Entrambi delegate e datasource sono riferimenti non citati. Ciò significa che c1 e c2 verranno rilasciati non appena si esce dall'ambito. Prova a dichiarare c1 e c2 come proprietà della classe.

I riferimenti noti non creano una presa sicura sull'oggetto indicato (ad esempio non aumentano il conteggio di ritenzione per impedire a ARC di deallocare l'oggetto indicato).

Assicurarsi inoltre di rimuovere le proprietà del delegato e dell'origine dati dei pick-up dal generatore di interfacce.

class WeightWheelInputViewController: UIViewController { 
    @IBOutlet weak var picker1: UIPickerView!   
    @IBOutlet weak var picker2: UIPickerView! 

    var c1 : WeightWheelController! 
    var c2 : WeightWheelController! 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     c1 = WeightWheelController(pickerInterval: 150) 

     c2 = WeightWheelController(pickerInterval: 10) 

     picker1.dataSource = c1 
     picker1.delegate = c1 

     picker2.dataSource = c2 
     picker2.delegate = c2 
    } 

    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
    } 
} 
+3

Ottima risposta! Ha funzionato subito fuori dagli schemi! Grazie mille!!! Tuttavia, ciò che non capisco è questo: in Java si potrebbe fare ciò che ho codificato sopra, e il GC non raccoglierà gli oggetti con il riferimento "debole", perché ora sono referenziati da PickerView. In che modo gestirlo in modo così diverso? – Christian

+0

bene. per questo è necessario conoscere il conteggio dei riferimenti automatici (ARC). Ti suggerisco di leggere la documentazione di Apple a riguardo. https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html – rakeshbs

+1

Risposta stupenda. Stavo impazzendo. Grazie mille! –

Problemi correlati