UIViewController의 하위 클래스에 대한 사용자 지정 초기화를 작성하는 데 문제가 있습니다. 기본적으로 속성을 직접 설정하는 대신 viewController의 init 메서드를 통해 종속성을 전달하고 싶습니다. viewControllerB.property = value
그래서 내 viewController에 대한 사용자 정의 초기화를 만들고 슈퍼 지정 초기화를 호출했습니다.
init(meme: Meme?) {
self.meme = meme
super.init(nibName: nil, bundle: nil)
}
뷰 컨트롤러 인터페이스는 스토리 보드에 있으며 사용자 지정 클래스의 인터페이스도 뷰 컨트롤러로 만들었습니다. 그리고 Swift는이 메소드 내에서 아무것도하지 않더라도이 init 메소드를 호출해야합니다. 그렇지 않으면 컴파일러가 불평합니다 …
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
문제는 MyViewController(meme: meme)
내 viewController에서 속성을 초기화하지 않는 사용자 지정 초기화를 호출하려고 할 때입니다 .
디버깅을 시도하고 있었는데, viewController에서 발견하고 init(coder aDecoder: NSCoder)
먼저 호출 한 다음 나중에 사용자 지정 초기화를 호출했습니다. 그러나이 두 init 메서드는 다른 self
메모리 주소를 반환 합니다.
내 viewController의 init에 문제가 있다고 의심되며 항상 구현이없는으로 반환 self
됩니다 init?(coder aDecoder: NSCoder)
.
누구든지 viewController에 대한 사용자 정의 초기화를 올바르게 만드는 방법을 알고 있습니까? 참고 : 내 viewController의 인터페이스는 스토리 보드에 설정되어 있습니다.
다음은 내 viewController 코드입니다.
class MemeDetailVC : UIViewController {
var meme : Meme!
@IBOutlet weak var editedImage: UIImageView!
// TODO: incorrect init
init(meme: Meme?) {
self.meme = meme
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func viewDidLoad() {
/// setup nav title
title = "Detail Meme"
super.viewDidLoad()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
editedImage = UIImageView(image: meme.editedImage)
}
}
답변
위의 답변 중 하나에서 지정 했으므로 사용자 정의 초기화 방법과 스토리 보드를 모두 사용할 수 없습니다. 그러나 여전히 정적 메서드를 사용하여 스토리 보드에서 ViewController를 인스턴스화하고 추가 설정을 수행 할 수 있습니다. 다음과 같이 표시됩니다.
class MemeDetailVC : UIViewController {
var meme : Meme!
static func makeMemeDetailVC(meme: Meme) -> MemeDetailVC {
let newViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("IdentifierOfYouViewController") as! MemeDetailVC
newViewController.meme = meme
return newViewController
}
}
스토리 보드에서 뷰 컨트롤러 식별자로 IdentifierOfYouViewController를 지정하는 것을 잊지 마십시오. 위 코드에서 스토리 보드의 이름을 변경해야 할 수도 있습니다.
답변
스토리 보드에서 초기화 할 때 사용자 지정 이니셜 라이저를 사용할 수 없습니다.를 사용 init?(coder aDecoder: NSCoder)
하여 컨트롤러를 초기화하기 위해 스토리 보드를 설계 한 방법을 사용 합니다. 그러나 데이터를 UIViewController
.
뷰 컨트롤러의 이름이 포함 detail
되어 있으므로 다른 컨트롤러에서 가져 왔다고 가정합니다. 이 경우 prepareForSegue
메서드를 사용 하여 세부 정보로 데이터를 보낼 수 있습니다 (Swift 3입니다).
override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "identifier" {
if let controller = segue.destinationViewController as? MemeDetailVC {
controller.meme = "Meme"
}
}
}
테스트 목적 String
대신 유형의 속성을 사용했습니다 Meme
. 또한 올바른 segue 식별자를 전달했는지 확인하십시오 ( "identifier"
자리 표시 자일 뿐임 ).
답변
@Caleb Kleveter가 지적했듯이 스토리 보드에서 초기화하는 동안 사용자 지정 초기화 프로그램을 사용할 수 없습니다.
하지만 Storyboard에서 뷰 컨트롤러 객체를 인스턴스화하고 뷰 컨트롤러 객체를 반환하는 팩토리 / 클래스 메서드를 사용하여 문제를 해결할 수 있습니다. 이것은 꽤 멋진 방법이라고 생각합니다.
참고 : 이것은 질문에 대한 정확한 대답이 아니라 문제를 해결하기위한 해결 방법입니다.
MemeDetailVC 클래스에서 다음과 같이 클래스 메서드를 만듭니다.
// Considering your view controller resides in Main.storyboard and it's identifier is set to "MemeDetailVC"
class func `init`(meme: Meme) -> MemeDetailVC? {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "MemeDetailVC") as? MemeDetailVC
vc?.meme = meme
return vc
}
용법:
let memeDetailVC = MemeDetailVC.init(meme: Meme())
답변
이 작업을 수행 한 한 가지 방법은 편의 이니셜 라이저를 사용하는 것입니다.
class MemeDetailVC : UIViewController {
convenience init(meme: Meme) {
self.init()
self.meme = meme
}
}
그런 다음 MemeDetailVC를 다음과 같이 초기화합니다. let memeDetailVC = MemeDetailVC(theMeme)
이니셜 라이저에 대한 Apple의 문서 는 꽤 좋지만 개인적으로 가장 좋아하는 것은 Ray Wenderlich : Initialization in Depth 튜토리얼 시리즈입니다. 다양한 init 옵션과 작업을 수행하는 “적절한”방법에 대한 많은 설명 / 예제를 제공해야합니다.
편집 : 사용자 정의 뷰 컨트롤러에서 편의 이니셜 라이저를 사용할 수 있지만 스토리 보드 또는 스토리 보드 segue를 통해 초기화 할 때 사용자 정의 이니셜 라이저를 사용할 수 없다고 말하는 모든 사람이 맞습니다.
인터페이스가 스토리 보드에 설정되어 있고 컨트롤러를 완전히 프로그래밍 방식으로 생성하는 경우, 필요한 초기화를 처리 할 필요가 없기 때문에 편의 이니셜 라이저가 수행하려는 작업을 수행하는 가장 쉬운 방법 일 것입니다. NSCoder (내가 아직도 이해하지 못함).
스토리 보드를 통해 뷰 컨트롤러를 얻는 경우 @Caleb Kleveter의 답변 을 따라 뷰 컨트롤러를 원하는 하위 클래스로 캐스팅 한 다음 속성을 수동으로 설정해야합니다.
답변
원래 몇 가지 답변이 있었는데, 기본적으로 정확했지만 소 투표 및 삭제되었습니다. 대답은 할 수 없다는 것입니다.
스토리 보드 정의에서 작업 할 때 뷰 컨트롤러 인스턴스는 모두 보관됩니다. 따라서 초기화하려면 사용해야 init?(coder...
합니다. 는 coder
모든 설정 / 뷰 정보의 출처입니다.
따라서이 경우 사용자 지정 매개 변수를 사용하여 다른 초기화 함수를 호출 할 수도 없습니다. segue를 준비 할 때 속성으로 설정하거나 segue를 버리고 스토리 보드에서 직접 인스턴스를로드하고 구성 할 수 있습니다 (기본적으로 스토리 보드를 사용하는 팩토리 패턴).
모든 경우에 SDK 필수 초기화 기능을 사용하고 나중에 추가 매개 변수를 전달합니다.
답변
스위프트 5
다음과 같이 사용자 정의 이니셜 라이저를 작성할 수 있습니다->
class MyFooClass: UIViewController {
var foo: Foo?
init(with foo: Foo) {
self.foo = foo
super.init(nibName: nil, bundle: nil)
}
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.foo = nil
}
}
답변
UIViewController
클래스 NSCoding
는 다음과 같이 정의 된 프로토콜을 따릅니다 .
public protocol NSCoding {
public func encode(with aCoder: NSCoder)
public init?(coder aDecoder: NSCoder) // NS_DESIGNATED_INITIALIZER
}
그래서 UIViewController
두 개의 지정된 이니셜 라이저 init?(coder aDecoder: NSCoder)
와 init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?)
.
Storyborad 호출 init?(coder aDecoder: NSCoder)
초기화하기 위해서 직접 UIViewController
하고 UIView
당신이 매개 변수를 전달 할 여지가 없습니다.
번거로운 해결 방법 중 하나는 임시 캐시를 사용하는 것입니다.
class TempCache{
static let sharedInstance = TempCache()
var meme: Meme?
}
TempCache.sharedInstance.meme = meme // call this before init your ViewController
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder);
self.meme = TempCache.sharedInstance.meme
}
