Swift'de bir UIViewController alt sınıfı için nasıl özel bir başlatıcı yapabilirim?


95

Bu daha önce sorulmuşsa özür dilerim, çok fazla araştırma yaptım ve birçok yanıt, işler farklı olduğunda önceki Swift betalarından geliyor. Kesin bir cevap bulamıyorum.

Alt sınıf yapmak istiyorum UIViewController ve onu kodda kolayca ayarlamama izin veren özel bir başlatıcıya sahip olmak . Bunu Swift'de yapmakta sorun yaşıyorum.

Daha sonra görünüm denetleyicisiyle kullanacağım init()belirli bir işlevi iletmek için kullanabileceğim bir işlev istiyorum NSURL. Aklımda bir şeye benziyorinit(withImageURL: NSURL) . Bu işlevi eklersem, init(coder: NSCoder)işlevi eklememi ister .

Bunun süper sınıfta required anahtar kelimeyleYani bunu alt sınıfta mı yapmalıyım? Ekliyorum:

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

Şimdi ne olacak? Özel başlatıcım birconvenience tane olarak mi? Belirlenmiş mi? Süper başlatıcı çağırıyor muyum? Aynı sınıftan bir başlatıcı mı?

Özel başlatıcımı bir UIViewControlleralt sınıfa nasıl eklerim ?


Başlatıcılar, programla oluşturulmuş viewControllers için iyidir, ancak film şeridi aracılığıyla oluşturulan görüntü denetleyicileri için şansınız yok ve bu konuda yolunuzu ayırmanız gerekiyor
Honey

Yanıtlar:


161
class ViewController: UIViewController {

    var imageURL: NSURL?

    // this is a convenient way to create this view controller without a imageURL
    convenience init() {
        self.init(imageURL: nil)
    }

    init(imageURL: NSURL?) {
        self.imageURL = imageURL
        super.init(nibName: nil, bundle: nil)
    }

    // if this view controller is loaded from a storyboard, imageURL will be nil

    /* Xcode 6
    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    */

    // Xcode 7 & 8
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
}

imageURL bunun yerine sabit olabilir mi? ("let imageURL: NSURL?)
Van Du Tran 15

2
xCode 7 çalışmıyorsa, gerekli kurucu sınıf düzeyi özelliğini başlatamıyor, benim durumumda bir Int, NSURL değil mi?
Chris Hayes

1
@NikolaLukic - Biz arayarak sınıfın yeni bir örneğini oluşturur edebilir ViewController(), ViewController(imageURL: url)ya da bir film şeridinden yüklemeden.
ylin0x81

3
Benimkini required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") }başka türlü yazmam gerekiyordu, aramada Mülkiyetsuper.init(coder: aDecoder) hatası alıyordumself.somePropertysuper.init
Honey

1
Bunun nasıl bağlantılı olduğundan emin değilim. Saf kod yapıyorsanız, özelliklerinizi init(coder: aDecoder). fatalErrorİrade yeterli durumdadır
Bal

26

Kodda UI yazanlar için

class Your_ViewController : UIViewController {

    let your_property : String

    init(your_property: String) {
        self.your_property = your_property
        super.init(nibName: nil, bundle: nil)
    }

    override func viewDidLoad() {
        super.viewDidLoad()

    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) is not supported")
    }
}

12

Bu diğer cevaplara çok benziyor, ancak bazı açıklamalarla. Kabul edilen yanıt yanıltıcıdır çünkü özelliği isteğe bağlıdır ve init?(coder: NSCoder)ZORUNLU her özelliği başlatmanız gerektiği ve bunun için tek çözümün bir fatalError(). Nihayetinde mülklerinizi isteğe bağlı hale getirerek kurtulabilirsiniz, ancak bu OP'nin sorusuna gerçekten cevap vermez.

// Think more of a OnlyNibOrProgrammatic_NOTStoryboardViewController
class ViewController: UIViewController {

    let name: String

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

    // I don't have a nib. It's all through my code.
    init(name: String) {
        self.name = name

        super.init(nibName: nil, bundle: nil)
    }

    // I have a nib. I'd like to use my nib and also initialze the `name` property
    init(name: String, nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle? ) {
        self.name = name
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    }

    // when you do storyboard.instantiateViewController(withIdentifier: "ViewController")
    // The SYSTEM will never call this!
    // it wants to call the required initializer!

    init?(name: String, coder aDecoder: NSCoder) {
        self.name = "name"
        super.init(coder: aDecoder)
    }

    // when you do storyboard.instantiateViewController(withIdentifier: "ViewController")
    // The SYSTEM WILL call this!
    // because this is its required initializer!
    // but what are you going to do for your `name` property?!
    // are you just going to do `self.name = "default Name" just to make it compile?!
    // Since you can't do anything then it's just best to leave it as `fatalError()`
    required init?(coder aDecoder: NSCoder) {
        fatalError("I WILL NEVER instantiate through storyboard! It's impossible to initialize super.init?(coder aDecoder: NSCoder) with any other parameter")
    }
}

Temelde onu film şeridinden yüklemekten vazgeçmelisiniz. Neden?

Bir viewController çağırdığınızda Çünkü storyboard.instantiateViewController(withIdentifier: "viewController")o UIKit onun bir şey ve çağrı yapacak

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

Bu çağrıyı asla başka bir init yöntemine yönlendiremezsiniz.

Dokümanlar instantiateViewController(withIdentifier:):

Programlı olarak sunum yapmak üzere bir görünüm denetleyici nesnesi oluşturmak için bu yöntemi kullanın. Bu yöntemi her çağırdığınızda, init(coder:)yöntemi kullanarak yeni bir görünüm denetleyicisi örneği oluşturur .

Yine de programla oluşturulmuş viewController veya uç tarafından oluşturulan viewControllers için bu çağrıyı yukarıda gösterildiği gibi yeniden yönlendirebilirsiniz.


5

Kullanışlı başlatıcılar ikincildir ve bir sınıf için başlatıcıları destekler. Atanan başlatıcının bazı parametreleri varsayılan değerlere ayarlanmış olarak, aynı sınıftan atanmış bir başlatıcıyı çağırmak için bir kullanışlı başlatıcı tanımlayabilirsiniz. Ayrıca, belirli bir kullanım durumu veya girdi değeri türü için o sınıfın bir örneğini oluşturmak için bir kolaylık başlatıcı da tanımlayabilirsiniz.

Burada belgelenmiştir .


0

Örneğin, bir açılır bilgi penceresi için özel bir başlatmaya ihtiyacınız varsa, aşağıdaki yaklaşımı kullanabilirsiniz:

NibName ve bundle ile süper initi kullanan ve bundan sonra görünüm hiyerarşisinin yükünü zorlamak için view özelliğine erişen özel bir init oluşturun.

Daha sonra, viewDidLoad işlevinde, görünümleri başlatmada aktarılan parametrelerle yapılandırabilirsiniz.

import UIKit

struct Player {
    let name: String
    let age: Int
}

class VC: UIViewController {


@IBOutlet weak var playerName: UILabel!

let player: Player

init(player: Player) {
    self.player = player
    super.init(nibName: "VC", bundle: Bundle.main)
    if let view = view, view.isHidden {}
}

override func viewDidLoad() {
    super.viewDidLoad()
    configure()
}

func configure() {
    playerName.text = player.name + "\(player.age)"
}
}

func showPlayerVC() {
    let foo = Player(name: "bar", age: 666)
    let vc = VC(player: foo)
    present(vc, animated: true, completion: nil)
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.