8

Mam dwa różne UIPickerViews w moim widoku. Działają wspaniale, gdy ustawiam źródło danych i delegata w widoku, w którym są hostowane za pośrednictwem scenorysu, ale kiedy próbuję to zrobić za pomocą kodu, jak opisano poniżej, to nie działa.UIPickerView z "zewnętrznym" DataSource i Delegatem w Swift

Obydwaj zbieracze muszą mieć różne dane do wyświetlenia (a może nawet różne zachowania dla delegata). W związku z tym chciałbym programowo podłączyć je do różnych źródeł danych.

Próbowałem utworzyć własną klasę implementującą UIPickerViewDataSource- i UIPickerViewDelegate-Protocols i łącząc obiekty tej klasy z moim PickerViews, ale to nie działa. Jest wyjątek w czasie wykonywania terminating with uncaught exception of type NSException stwierdzając to:

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' 

Jak mogę uzyskać to do pracy? Co mnie ominęło? Tu jest mój kodu:

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() 
    } 
} 

KRÓTKI UPDATE:

W tej kwestii odkryłem, że można użyć różne znaczniki dla różnych widoków próbnych. To byłaby jedna opcja; jednak nie podoba mi się to. Chciałbym raczej zastosować podejście MVC i podłączyć różne kontrolery do każdego selektora. Czy to w żaden sposób nie jest możliwe?

Odpowiedz

13

Zarówno delegate, jak i datasource są odniesieniami. Oznacza to, że c1 i c2 zostaną zwolnione, gdy tylko wykroczymy poza zakres. Spróbuj zadeklarować c1 i c2 jako właściwości klasy.

Odwołane referencje nie powodują silnego wstrzymania dla obiektu, na który się powołuje (a.k.a. nie powodują zwiększenia liczby zatrzymań w celu uniemożliwienia ARC zwolnienia przydzielonego obiektu).

Upewnij się również, że usunąłeś właściwości delegata i źródła danych z widoku pickerviews z kreatora interfejsu.

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

Świetna odpowiedź! Pracował od razu po wyjęciu z pudełka! Dziękuję bardzo!!! Jednak nie rozumiem tego: w Javie można zrobić to, co napisałem powyżej, a GC nie będzie zbierać obiektów z "słabym" odniesieniem, ponieważ są one teraz przywoływane przez PickerView. Jak szybka obsługa jest inna? – Christian

+0

oraz. do tego trzeba się nauczyć o automatycznym liczeniu odwołań (ARC). Sugeruję przeczytanie dokumentacji Apple na ten temat. https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html – rakeshbs

+1

Ogromna odpowiedź. Oszalałem. Stukrotne dzięki! –