Swiftの他のクラスに処理してもらう時のアレコレ
delegate
処理を移譲する仕組み
protocol MyDelegate: class {
func tapped(_ button: Button)
}
final class Button: UIView {
weak var delegate: MyDelegate? = nil
func touchesEnded() {
delegate?.tapped(self)
}
}
大体の場合はプロトコルとクラスがセットになる
class ViewController: UIViewController, MyDelegate {
@IBOutlet weak var button: Button!
func viewDidLoad() {
button.delegate = self
}
func tapped(_ button: Button) {
print("タップされた")
}
}
このように使う。
delegate?.tapped(self)
が呼ばれると、ViewControllerのfunc tapped(_ button: Button)
が呼ばれる。
この例ではButtonとViewControllerという2つのクラスが存在しているが、
ButtonからViewControllerのメソッドを呼んで実行していると考えるのが分かりやすいと思う。
これが一番スタンダードなコールバックだと思う。
Blocks
ObjCの時代によく見たやつ
class ViewController: UIViewController {
@IBOutlet weak var button: Button!
override func viewDidLoad() {
super.viewDidLoad()
button.closure = { (button) in
print("タップされた")
}
}
}
class Button: UIView {
var closure: ((Button)->Void)? = nil
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
closure?(self)
}
}
これは要するに、((Button)->Void)
という構造の処理を保持して、タップされた時に実行しているという感じ。
便利だけど、強参照・弱参照とか考えないとヤバい感じになりがち。
Notification
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(tapped), name: Notification.Name(rawValue: "tap.action"), object: nil)
}
func tapped(_ notification: Notification) {
print("タップされた")
}
}
class Button: UIView {
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
NotificationCenter.default.post(Notification(name: Notification.Name(rawValue: "tap.action")))
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(tapped), name: Notification.Name(rawValue: "tap.action"), object: nil)
}
func tapped(_ notification: Notification) {
print("タップされた")
}
}
class Button: UIView {
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
NotificationCenter.default.post(Notification(name: Notification.Name(rawValue: "tap.action")))
}
}
もはやインスタンスがどこにあろうと処理を別の所で出来る強いやつ。
上の例だとボタンが2つある時とかはどっちが押されたかとか判別するのにはNotificationにタグ情報を入れたりしないといけないので骨が折れる。
基本的には一箇所で起きるイベントに対して多くのクラスでアクションが行われる時に使う。
処理も追いにくいのでなるべく使わないでほしいやつ。
RxSwift
class ViewController: UIViewController {
@IBOutlet weak var button: Button!
let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
button.tapped.subscribe(onNext: {
print("タップされた")
}).disposed(by: disposeBag)
}
}
class Button: UIView {
let tapped = PublishSubject<Void>()
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
tapped.onNext()
}
}
class ViewController: UIViewController {
@IBOutlet weak var button: Button!
let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
button.tapped.subscribe(onNext: {
print("タップされた")
}).disposed(by: disposeBag)
}
}
class Button: UIView {
let tapped = PublishSubject<Void>()
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
tapped.onNext()
}
}
Blocksに似てるけど、RxSwiftというライブラリを使った書き方。
RxSwiftによるオペレータの恩恵が受けれる。(スレッドの変更や、リトライなど)
やったらダメなやつ
class ViewController: UIViewController {
@IBOutlet weak var button: Button!
override func viewDidLoad() {
super.viewDidLoad()
button.viewController = self
}
func tapped() {
print("タップされた")
}
}
class Button: UIView {
var viewController: ViewController?
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
viewController?.tapped()
}
}
class ViewController: UIViewController {
@IBOutlet weak var button: Button!
override func viewDidLoad() {
super.viewDidLoad()
button.viewController = self
}
func tapped() {
print("タップされた")
}
}
class Button: UIView {
var viewController: ViewController?
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
viewController?.tapped()
}
}
ButtonにViewControllerを持つパターン。
お互いにお互いのインスタンスを保持してしまうので、メモリから開放されなくなる。
こういう場合の回避方法
class ViewController: UIViewController {
@IBOutlet weak var button: Button!
override func viewDidLoad() {
super.viewDidLoad()
button.viewController = self
}
func tapped() {
print("タップされた")
}
}
class Button: UIView {
weak var viewController: ViewController?
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
viewController?.tapped()
}
}
子が親を持つ際にweakにすると、弱参照になるのでViewControllerはButtonに保持されずViewControllerの開放に合わせてButtonも開放される。
Author And Source
この問題について(Swiftの他のクラスに処理してもらう時のアレコレ), 我々は、より多くの情報をここで見つけました https://qiita.com/noppefoxwolf/items/22d0028784f768511d57著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .