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 내가 만든 s및 i옵션 여기 것들을 간단하게 유지. 선택 사항이 아닌 경우 필수 이니셜 라이저에서 초기화해야합니다. 그들에게 할 수 선택 수단 만들기 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.