Swift에서 UIView 서브 클래스에 대한 사용자 정의 초기화를 작성하는 방법


125

a 와 inita로 UIView서브 클래스를 만들고 싶다고 가정 해보십시오 .StringInt

서브 클래 싱하는 경우 Swift에서 어떻게해야 UIView합니까? 방금 사용자 정의 init()함수를 만들지 만 매개 변수가 String 및 Int이면 "init.r에서 반환하기 전에 super.init ()가 호출되지 않는다"고 알려줍니다.

그리고 전화 super.init()하면 지정된 이니셜 라이저를 사용해야한다고 들었습니다. 거기서 무엇을 사용해야합니까? 프레임 버전? 코더 버전? 양자 모두? 왜?

답변:


207

init(frame:)버전은 기본 이니셜이다. 인스턴스 변수를 초기화 한 후에 만 ​​호출해야합니다. 이 뷰가 펜촉에서 재구성되는 경우 사용자 정의 이니셜 라이저가 호출되지 않고 대신 init?(coder:)버전이 호출됩니다. Swift는 이제 required의 구현이 필요하므로 init?(coder:)아래 예제를 업데이트하고 let변수 선언을 var선택적으로 변경했습니다 . 이 경우 awakeFromNib()나중에 또는 나중에 초기화합니다 .

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
그런 다음 반드시 그들을 만드십시오 var. 그러나 Swift의 기본 모범 사례는 변수 let를 선언 할 이유가없는 한 변수 를 선언하는 것 var입니다. 위의 코드 예제에서 그렇게 할 이유가 없었으므로 let.
울프 맥 날리

2
이 코드는 컴파일되지 않습니다. 필요한 이니셜 라이저를 구현해야합니다 init(coder:).
Decade Moon

3
이것이 몇 년 전에 어떻게 컴파일되었는지 흥미로운. 요즘은 init (coder :)에서 "super.init 호출시 속성 self.s가 초기화되지 않았다"고 불평합니다
mafiOSo

Swift 3.1의 수정 된 예. UIKit을 가져 오는 놀이터에서 컴파일합니다.
울프 맥 날리

1
@LightNight 내가 만든 si옵션 여기 것들을 간단하게 유지. 선택 사항이 아닌 경우 필수 이니셜 라이저에서 초기화해야합니다. 그들에게 할 수 선택 수단 만들기 nil할 때 super.init()호출됩니다. 선택 사항이 아닌 경우 super.init ()를 호출하기 전에 할당해야합니다.
울프 맥 날리

32

지정 및 필수에 대한 공통 초기화를 작성합니다. 편의상 나는 init(frame:)0 프레임으로 위임 합니다.

프레임이없는 것은 일반적으로 뷰가 ViewController의 뷰 안에 있기 때문에 문제가되지 않습니다. 사용자 정의보기는 슈퍼 뷰 호출시 layoutSubviews()또는 서브 뷰를 레이아웃 할 수있는 안전하고 좋은 기회를 얻습니다 updateConstraints(). 이 두 함수는 뷰 계층 전체에서 시스템에 의해 재귀 적으로 호출됩니다. 당신도 사용할 수 있습니다 updateContstraints()또는 layoutSubviews(). updateContstraints()먼저 호출 layoutSubviews()됩니다. 에서 updateConstraints()확인 슈퍼 호출하는 마지막 . 에서 먼저layoutSubviews() super를 호출하십시오 .

내가하는 일은 다음과 같습니다.

@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
이 작업 안 : 메서드 호출는 super.init 초기화하기 전에 'commonInit'에서 '자기'를 사용하는 자기
나 서프 라이더

1
self.init 호출 후 사용자 정의 인수를 초기화하십시오. 내 답변을 업데이트했습니다.
MH175

1
그러나 commonInit메소드 에서 일부 특성을 초기화하려는 super경우 super호출하기 전에 모든 특성을 초기화해야하므로이 경우 이후 에 배치 할 수 없습니다 . 그것은 죽은 루프처럼 보입니다.
surfrider

1
이것은 스위프트 초기화가 종종 작동하는 방법입니다 : "2 단계 초기화"를 검색하십시오. 암시 적으로 래핑되지 않은 옵션을 사용할 수 있지만 권장하지는 않습니다. 아키텍처는 특히 뷰를 처리 할 때 모든 로컬 속성을 초기화해야합니다. 이 commonInit () 메소드를 수백 가지 뷰에 사용했습니다. 작동
MH175

17

Swift의 iOS 9에서 수행하는 방법은 다음과 같습니다.

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"); }
}

다음은 예제가 포함 된 전체 프로젝트입니다.


2
이것은 뷰의 전체 디스플레이를 사용합니다
RaptoX

1
네! 일부 하위 뷰에 관심이 있다면 저에게 알려 주시면뿐만 아니라이 게시합니다
J-디즐

1
fatalError가 있다는 것은 필요한 init에 코드를 넣을 필요가 없다는 것을 의미하기 때문에이 답변이 가장 좋습니다.
카터 메 드린

1
@ J-Dizzle, 부분 뷰 솔루션을보고 싶습니다.
Ari Lacenski

당신의 대답은 받아 들여진 대답의 반대라고 말하지 않습니까? 당신은 이후 super.init에 사용자 정의를 수행하는 것을 의미 하지만, 그는 전에 수행해야한다고 말했다 super.init...
Honey

11

Swift에서 iOS에서 서브 뷰를 수행하는 방법은 다음과 같습니다.

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 () 호출을 잘 사용합니다. 사용되지 않은 이니셜 라이저에서 경고를 침묵시키기 위해 옵션을 사용해야했습니다. 이것은 바로 닥쳤다! 감사.
Mike Critchley
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.