Swift'de bir UIView alt sınıfı için özel bir init nasıl yazabilirim?


125

Say İstiyorum initbir UIViewbir ile alt sınıf Stringve bir Int.

Sadece alt sınıflara ayırıyorsam bunu Swift'de nasıl yaparım UIView? Yalnızca özel bir init()işlev yaparsam, ancak parametreler bir String ve bir Int ise, bana "super.init () 'in başlatıcıdan dönmeden önce çağrılmadığını" söyler.

Ve super.init()ararsam, belirlenmiş bir başlatıcı kullanmam gerektiği söylendi. Orada ne kullanmalıyım? Çerçeve versiyonu mu? Kodlayıcı versiyonu mu? Her ikisi de? Neden?

Yanıtlar:


207

init(frame:)Versiyon varsayılan başlatıcısı olduğunu. Bunu yalnızca örnek değişkenlerinizi başlattıktan sonra çağırmalısınız. Bu görünüm bir Uçtan yeniden oluşturuluyorsa, özel başlatıcınız çağrılmayacak ve onun yerine init?(coder:)sürüm çağrılacaktır. Swift artık gerekli olanın uygulanmasını gerektirdiğinden init?(coder:), aşağıdaki örneği güncelledim ve letdeğişken bildirimlerini varve isteğe bağlı olarak değiştirdim. Bu durumda, onları içinde awakeFromNib()veya daha sonra başlatırsınız .

class TestView : UIView {
    var s: String?
    var i: Int?
    init(s: String, i: Int) {
        self.s = s
        self.i = i
        super.init(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
    }

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

5
O zaman elbette onları yapın var. Ancak Swift'deki varsayılan en iyi uygulama, letonları bildirmek için bir neden olmadıkça değişkenleri bildirmektir var. Dolayısıyla, yukarıdaki kod örneğimde bunu yapmak için böyle bir neden yoktu let.
Wolf McNally

2
Bu kod derlenmez. Gerekli başlatıcıyı uygulamanız gerekir init(coder:).
Decade Moon

3
bunun yıllar önce nasıl derlendiği ilginç. Bugünlerde, init (kodlayıcı :) altında "Mülk özleri super.init çağrısında başlatılmadı" şikayet ediyor
mafiOSo

Swift 3.1 için sabit örnek. UIKit ithal eden bir oyun alanı altında derler.
Wolf McNally

1
@ LightNight yaptım sve iburada işleri basitleştirmek için İsteğe bağlı. İsteğe bağlı değillerse, gerekli başlatıcıda da başlatılmaları gerekir. Onlara olmak olsun opsiyonel araçlar yapma nilsırasında super.init()denir. İsteğe bağlı olmasalardı, gerçekten de super.init () çağrılmadan önce atanmaları gerekirdi.
Kurt McNally

33

Belirtilen ve gerekli olan için ortak bir init oluşturuyorum. Kolaylık sağlamak için init(frame:)sıfır çerçevesiyle delege ediyorum .

Sıfır çerçeveye sahip olmak bir sorun değildir çünkü görünüm tipik olarak ViewController görünümünün içindedir; özel görünümünüz, aramaları gözetim altında görüntülediğinde layoutSubviews()veya updateConstraints(). Bu iki işlev, sistem tarafından görünüm hiyerarşisi boyunca yinelemeli olarak çağrılır. Ya kullanabilir updateContstraints()veya layoutSubviews(). updateContstraints()önce denir, sonra layoutSubviews(). Gelen updateConstraints()marka emin süper aramaya son . Olarak layoutSubviews(), süper çağrı ilk .

İşte yaptığım şey:

@IBDesignable
class MyView: UIView {

      convenience init(args: Whatever) {
          self.init(frame: CGRect.zero)
          //assign custom vars
      }

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

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

      override func prepareForInterfaceBuilder() {
           super.prepareForInterfaceBuilder()
           commonInit()
      }

      private func commonInit() {
           //custom initialization
      }

      override func updateConstraints() {
           //set subview constraints here
           super.updateConstraints()
      }

      override func layoutSubviews() {
           super.layoutSubviews()
           //manually set subview frames here
      }

}

1
Çalışmamalı
super.init,

1
Self.init çağrısından sonra özel bağımsız değişkenleri başlatın. Cevabım güncellendi.
MH175

1
Ama ya commonInityöntemdeki bazı özellikleri başlatmak istiyorsanız , ancak superbu durumda onu sonrasına yerleştiremezseniz , çünkü çağrmadan ÖNCE tüm özellikleri başlatmanız gerekir super. Lol, ölü döngü gibi görünüyor.
surfrider

1
Swift başlatma genellikle böyle çalışır: "iki aşamalı başlatma" için arama yapın. Örtük olarak sarmalanmamış seçenekleri kullanabilirsiniz, ancak buna karşı öneririm. Mimariniz, özellikle görünümlerle uğraşırken, tüm yerel özellikleri başlatmalıdır. Bu commonInit () yöntemini şimdi yüzlerce görünümde kullandım. Çalışıyor
MH175

17

Swift'de iOS 9'da bunu nasıl yapıyorum -

import UIKit

class CustomView : UIView {

    init() {
        super.init(frame: UIScreen.mainScreen().bounds);

        //for debug validation
        self.backgroundColor = UIColor.blueColor();
        print("My Custom Init");

        return;
    }

    required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented"); }
}

İşte örnek içeren tam bir proje:


2
bu, View için tüm ekranı kullanır
RaptoX

1
Evet! Kısmi bir alt görünümle ilgileniyorsanız, bana bildirin ve bunu da
göndereceğim

1
Bu yanıtı en çok beğendim, çünkü fatalError'a sahip olmak, gerekli init'e herhangi bir kod koymam gerekmediği anlamına geliyor.
Carter Medlin

1
@ J-Dizzle, kısmi görünümler için çözümü görmek istiyorum.
Ari Lacenski

Cevabınız kabul edilen cevabın tersini söylemiyor mu? Demek istediğim, özelleştirmeyi daha sonra yapıyorsun super.init, ama daha önce yapılması gerektiğini söyledi super.init...
Tatlım

11

Swift'de iOS'ta nasıl bir Subview yaparım -

class CustomSubview : UIView {

    init() {
        super.init(frame: UIScreen.mainScreen().bounds);

        let windowHeight : CGFloat = 150;
        let windowWidth  : CGFloat = 360;

        self.backgroundColor = UIColor.whiteColor();
        self.frame = CGRectMake(0, 0, windowWidth, windowHeight);
        self.center = CGPoint(x: UIScreen.mainScreen().bounds.width/2, y: 375);

        //for debug validation
        self.backgroundColor = UIColor.grayColor();
        print("My Custom Init");

        return;
    }

    required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented"); }
}

4
FatalError () çağrısının güzel kullanımı. Kullanılmayan bir başlatıcıdan gelen uyarıları susturmak için opsiyonelleri kullanmak zorundaydım. Bu hemen kapayın! Teşekkürler.
Mike Critchley
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.