2017-12-15 3 views
0

예 : 텍스트를 완성 할 때 UIView에서 무언가를 업데이트해야하는 SpeechSynthesizer 클래스가 있습니다. SpeechSynthesizer 클래스는 AVSpeechSynthesizerDelegate 프로토콜을 따르므로 발화가 완료되면 didFinish 신호를 수신합니다. 여기에있는 개념은 ViewController가 너무 많은 대리자 메소드와 프로토콜의 긴 목록을 준수하지 않도록하는 것입니다. 해결 방법은 ViewController를 SpeechSynthesizer 초기화 매개 변수로 전달하는 것입니다. 이 방법을 사용하면 SpeechSynthesizer 클래스 내부에서 업데이트하려는 UIView에 연결된 ViewController에 액세스 할 수 있습니다. 필자가 싫어하는 점은 ViewController를 사용해야하는 모든 단일 클래스에 매개 변수로 전달하는 것이보기 흉하게 보인다는 것입니다. 그래서 나는 이것을 달성 할 수있는 다른 방법이 궁금합니다. 어떻게 함수에게이 그것에 의해 "라는"아니에요 이후의 ViewController에거기에있는 ViewController 초기화없이 참조로 전달하지 않고 UIView 사용자 지정 클래스 작동 방법 있는가?

private func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) 

반환 뭔가를 만들 수 있습니다

내가하는 질문을하는 또 다른 방법을 생각?

+2

위임 패턴을 사용해야합니다. 그것이 당신의 물건을 분리하는 적절한 방법입니다. – Paulw11

+0

또는 ViewController를 SpeechSynthesizer 초기화 매개 변수로 전달하는 대신 ViewController 조작을 수행하는 클로저를 전달할 수 있습니다. – Spads

답변

0

Quora에 답글을 추가했습니다. 여기에 복사 :

내 연구 코드를 테스트 한 후이 문제에 대한 2 가지 해결책을 제시합니다.

해결 방법 1 : 위임 패턴 :

은의 ViewController에서 사용자 지정 위임 프로토콜을 만들기

protocol ViewControllerDelegate:class { 
    func getViewLayer() -> CALayer 
} 

의 ViewController이 새로 만든 프로토콜을 준수하기 때문에 그것에 의해 정의 된 모든 기능을 구현해야합니다 그래서 ViewController 클래스의 어딘가에 추가하면 :

public func getViewLayer() -> CALayer { 
    return self.view.layer 
} 

N 내 사용자 정의 클래스, ReadTextMachine에, 나는 ViewControllerDelegate 유형

private weak var viewControllerDelegate: ViewControllerDelegate? 

변수가 약해야하며 프로토콜은 (는 "주기를 유지"문제를 해결 사용자 정의 모두 이후하기 위해 타입 클래스이어야의 변수를 추가 당신은 내 ReadTextMachine에 내가 추가되도록의 ViewController 내부의 함수 호출, 사용자 정의 클래스에서 이미 "호출"는 것을 이제 알 수 있습니다

클래스와의 ViewController 서로를 가리 킵니다) :

let viewLayer = self.viewControllerDelegate?.getViewLayer() 
self.cameraPreview = CameraPreview(session: self.camera.getSession(), container: viewLayer!) 
self.cameraPreview?.addPreview() 

위의 경우 , 내 CameraPreview (예,이 예제에서는 세 번째 클래스) 단순히 UIView에 카메라 미리보기 레이어를 추가합니다. 이를 위해 기본 View 레이어에 대한 액세스가 필요했습니다.

원래의 viewController 인스턴스가 코드의 아무 곳이나 참조로 전달되지 않았기 때문에 위 코드는 여전히 작동하지 않습니다. 이를 위해 우리는 ReadTextMachine에 다음 함수를 추가합니다

public func setViewControllerDelegate(viewController: ViewController) { // call this from the ViewController so that ViewController can be accessed from here. 
    self.viewControllerDelegate = viewController 
} 

은 위의 코드 조각은의 ViewController에서 호출되어야 할 것이다, 우리는 우리의 사용자 정의 클래스 (ReadTextMachine)를 인스턴스화 한 후, viewControllerDelegate가 가리키는 내부 있도록 ViewController. 그래서 우리의 ViewController.SWIFT :

operatingMode = ReadTextMachine() 
operatingMode.setViewControllerDelegate(viewController: self) 

또 다른 예와 설명이 LetsBuildThatApp에서이 video에서 찾을 수 있습니다. 나는 그걸로 대부분 내 솔루션을 파생. 위의 솔루션을 적용하는 개발

나의 현재 응용 프로그램은 여기에서 찾을 수 있습니다 : agu3rra/World-Aloud

해결 방법 2 : 공지 사항 및 관찰자 패턴

이 하나 이해하고 따라하기 쉬운 조금이다. 일반적인 아이디어는 사용자 정의 클래스가 관찰자 설정을 가지고 있기 때문에 ViewController에서 함수 호출을 트리거하는 메시지를 브로드 캐스트하도록하는 것입니다.

예를 들어, 내가 사용한 컨텍스트에서 AVCoundation을 사용하여 사진을 캡처하는 CameraCapture 클래스가 있습니다. 캡처 사진 트리거는 이미지를 즉시 반환 할 수 없습니다. iOS에는 실제로 이미지를 생성하기 전에 실행할 단계가 있기 때문입니다. CameraCapture에서 사진을 사용할 수있게 된 후 ReadTextMachine에서 활동을 다시 시작하길 원했습니다. (CustomClass 트리거 컨텍스트에서 적용하려면 ViewController 이벤트는 기본적으로 동일합니다. 둘 다 iOS 앱의 실제 클래스이기도합니다.)

내가 한 첫 번째 일은 앱의 여러 위치에서 사용할 것이므로 브로드 캐스트 기능을 만드는 것입니다. Xcode 프로젝트의 Utilities.swift 파일에이 파일을 넣었습니다.

public func broadcastNotification(name: String) { 
    let notification = Notification.Name(rawValue: name) 
    NotificationCenter.default.post(name: notification, object: nil) 
} 

위의 함수는 문자열을 사용하여 고유 한 알림 식별자 여야하며 NotificationCenter를 통해 브로드 캐스팅됩니다. 내 CameraCapture 클래스에서

, 나는 메시지의 고유 식별자 참조하는 정적 상수를 추가 : 이벤트 didFinishProcessingPhoto이 실행됩니다 때 AVFoundation을 알고있는 사람들을 위해

static let NOTIFY_PHOTO_CAPTURED = "agu3rra.worldAloud.photo.captured" 

을, 사진은 사용할 수있는 말 때문에 그 중 내가 추가 :

broadcastNotification(name: CameraCapture.NOTIFY_PHOTO_CAPTURED) 

위의 내용은 이전에 정의한 유틸리티 기능에 대한 호출입니다. 개체가 해제 될 때, 그래서 관찰자를 제거

override init() { 
      super.init() 

      // Setup event observers 
      let notification1 = Notification.Name(rawValue: CameraCapture.NOTIFY_PHOTO_CAPTURED) 
      NotificationCenter.default.addObserver(self, 
                selector: #selector(self.processingDoneTakingPhoto), 
                name: notification1, 
                object: nil) 
    } 

deinit { 
NotificationCenter.default.removeObserver(self) // cleanup observer once instance no longer exists 
      } 

deinit에서 중요하다

내 ReadTextMachine 클래스는 그 통지를 잡을 수 있으려면

, 나는 (그 초기화에 다음)과 deinit 루틴을 추가 기억에서, 관찰자는 주변에 남아있다. 위의 구성된 관찰자는 ReadTextMachine 내부에서 함수 호출을 트리거합니다.

@IBAction private func processingDoneTakingPhoto() { 
    // does my stuff 
} 

그게 전부입니다! 다시 말하지만, 전체 Xcode 프로젝트는 프로젝트의 Git 저장소에서 다운로드 할 수 있습니다. agu3rra/World-Aloud

다른 사람들에게 유용 할 수 있기를 바랍니다.

건배!

관련 문제