質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Delegates

Delegatesとは、オブジェクト指向型プログラミングにおいて、あるオブジェクトの操作を一部の他のオブジェクトに代替させる手法のこと。オブジェクトは他のデリゲートに頼って関数を実行することができます。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

1700閲覧

Delegateを用いてpresentメソッドを呼び出したいが、Delegateの呼び出し元クラスのインスタンスが作成出来ない

ichina

総合スコア6

Delegates

Delegatesとは、オブジェクト指向型プログラミングにおいて、あるオブジェクトの操作を一部の他のオブジェクトに代替させる手法のこと。オブジェクトは他のデリゲートに頼って関数を実行することができます。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2020/10/01 16:08

【Swift】PresentationControllerでモーダルを表示したい
こちらの記事を参考にモーダルビューを作成しました。

このモーダルビューにメール送信画面を開くボタンを置き、尚且つビューのサイズとUIPartsのframe値をマルチデバイス対応させたかったのでUIPresentationControllerを継承したクラスにviewを新たに作成するメソッドを追加しました。
表示元となるViewControllerはmodal viewのサイズ情報を持っていないためSettingUIPresentationControllerクラスでUIPartsを配置しています。

SettingUIPresentationController

1protocol SendMailDelegate { 2 func sendMail() 3} 4 5func createView() -> UIView{ 6 let viewSize = (width:self.presentedView!.frame.width, height:self.presentedView!.frame.height) 7 let secondView = UIView.init(frame: self.labelProcessing.CGRectMake(0, 0, viewSize.width, viewSize.height)) 8 secondView.backgroundColor = .lightGray 9 10 let mailSendButton = UIButton(frame: CGRect.init(center: CGPoint.init(x: viewSize.width / 2, y: viewSize.height * (2/3)), size: CGSize.init(width: 100,height: 50))) 11 mailSendButton.setTitle("ご意見・ご要望はこちら", for: .normal) 12 mailSendButton.setTitleColor(UIColor.blue, for: .normal) 13 mailSendButton.addTarget(self, action: #selector(self.clickSendMailButton(sender:)), for: .touchUpInside) 14 15 16 mailSendButton.backgroundColor = .blue 17 secondView.addSubview(mailSendButton) 18 return secondView 19 } 20 21 22 var sendMailDelegate: SendMailDelegate? 23 @objc func clickSendMailButton(sender: UIButton){ 24 print("押したよ") 25 sendMailDelegate?.sendMail() 26 } 27

この時clickSendMailButton()が実行された時にUIViewControllerにメール送信画面を開く処理を委任したいのですが、
UIViewController側でSettingUIPresentationControllerをインスタンス化出来ず、sendMailDelegate=selfが書けません。


SettingViewController

1 override func viewDidLoad() { 2 super.viewDidLoad() 3 4 var settingUIPresentationController = SettingUIPresentationController() //コンパイルエラー 'init()' is unavailable 5 SettingUIPresentationController.sendMailDelegate = self //コンパイルエラー Instance member 'sendMailDelegate' cannot be used on type 'SettingUIPresentationController'; did you mean to use a value of this type instead? 6 7 }

試したこと

SettingUIPresentationControllerにデフォルトイニシャライザを追加
Cannot override 'init' which has been marked unavailableとコンパイルエラーになるだけでした

自分でdelegateを使うのが初めてで見よう見まねで書いてみたのですが、ネット上にはUITableViewCellのIBOutlet接続やstoryboardのidentifierを使ったインスタンス化ばかりでこういう場合のdelegateの書き方は見つかりませんでした。
そもそもこのような使い方が合ってるのかも分かりませんが、このような場合のdelegateの使い方をご教示いただけると幸いです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

Qiitaの記事を見て実装してみました。

ご自身で考えなければならないのはModalViewController.swift の中身で、delegate も含めこちらで宣言することになるかと思います。

モーダルウィンドウを管理するPresentationController.swift については、参照先のコードそのままで使うことになります。あえて手をいれるとすると、表示したいモーダルウィンドウの余白

Swift

1 let margin = (x: CGFloat(40), y: CGFloat(220.0))

の部分程度になります。

いただいているコードをもとに推測して作ったので、要件があっているかわかりませんが、おそらくこういうことを実現されたかったのではないでしょうか。

イメージ説明

実際には、「メールを送る」ボタンを押すとデバッグウインドウに表示が出るようになっていますが、視覚的にわかりにくいので、ViewController の背景色をランダムに変えるようにしています。

基本的な実装点や注意点はコード中にコメントを入れましたが、不明な点は追加でご質問いただけますでしょうか。

必要最低限のコードは以下の通りですが、プロジェクト全体も github におきましたので、必要に応じてそちらもご参照いただければと思います。

基本的に、PresentationController.swift については参照先のコードそのままで使えるのですが、たとえば余白サイズを動的に変更したいとなると、イニシャライザに多少手を加える必要がありますので、その場合には github のコードを参考にしてみていただけますでしょうか。

https://github.com/tsukubadepot/teratail-295368_PresentationController

  • ViewController.swift

Swift

1import UIKit 2 3class ViewController: UIViewController, UIViewControllerTransitioningDelegate { 4 5 override func viewDidLoad() { 6 super.viewDidLoad() 7 // Do any additional setup after loading the view. 8 } 9 10 @IBAction func modalAction(_ sender: AnyObject) { 11 let modalVC = self.storyboard?.instantiateViewController(withIdentifier: "modal") as! ModalViewController 12 modalVC.modalPresentationStyle = .custom 13 modalVC.transitioningDelegate = self 14 15 // MARK: - delegate の移譲先を設定 16 modalVC.sendMailDelegate = self 17 18 present(modalVC, animated: true, completion: nil) 19 } 20 21 func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? { 22 return PresentationController(presentedViewController: presented, presenting: presenting) 23 24 // MARK: - 上下マージンを PresentationController() で指定した値以外にしたい場合 25 //return PresentationController(presentedViewController: presented, presenting: presenting, viewMargin: CGPoint(x: 100, y: 100)) 26 } 27} 28 29// MARK: - ViewController 側での処理 30extension ViewController: SendMailDelegate { 31 func sendMail() { 32 print("ViewController 側で処理したよ。") 33 34 // わかりやすいように、背景色をランダムに変えてみる 35 view.backgroundColor = [ UIColor.red, UIColor.yellow, UIColor.green].randomElement() 36 } 37}
  • ModalViewController

Swift

1import UIKit 2 3// MARK: - プロトコルは class を継承させる。継承させなければ weak キーワードをつけることができない 4protocol SendMailDelegate: class { 5 func sendMail() 6} 7 8class ModalViewController: UIViewController { 9 // MARK: - ボタンのインスタンス 10 lazy var mailSendButton: UIButton = { 11 let button = UIButton(frame: .zero) 12 button.setTitle("ご意見・ご要望はこちら", for: .normal) 13 button.setTitleColor(UIColor.blue, for: .normal) 14 button.addTarget(self, action: #selector(self.clickSendMailButton(sender:)), for: .touchUpInside) 15 button.backgroundColor = .yellow 16 17 return button 18 }() 19 20 // MARK: - delegate に使うプロパティは、循環参照を防止するために weak キーワードをつける 21 weak var sendMailDelegate: SendMailDelegate? 22 23 override func viewDidLoad() { 24 super.viewDidLoad() 25 26 // Do any additional setup after loading the view. 27 self.view.backgroundColor = .lightGray 28 29 // MARK: - この段階では、標準の View Controller のサイズしか求まらない 30 let viewSize = (width: self.view.bounds.width, height: self.view.bounds.height) 31 print(#function, viewSize) 32 33 // ここでは、ボタンのインスタンスを作って、view に配置するだけ 34 self.view.addSubview(mailSendButton) 35 } 36 37 // MARK: - レイアウトする段階になって初めて実際のサイズが判明する 38 override func viewWillLayoutSubviews() { 39 super.viewWillLayoutSubviews() 40 41 // viewDidLoad で計算した viewSize と比較してみるとわかりやすい 42 let viewSize = (width: self.view.bounds.width, height: self.view.bounds.height) 43 print(#function, viewSize) 44 45 // ボタンをモーダルビューの中央に移動させ、文字が入るようにサイズを調整する 46 mailSendButton.center = CGPoint(x: viewSize.width / 2, y: viewSize.height / 2) 47 mailSendButton.sizeToFit() 48 } 49 50 @objc func clickSendMailButton(sender: UIButton){ 51 print("押したよ") 52 sendMailDelegate?.sendMail() 53 54 // ボタンを押したらモーダルウィンドウを閉じる 55 dismiss(animated: true, completion: nil) 56 } 57}

投稿2020/10/02 12:52

TsukubaDepot

総合スコア5086

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ichina

2020/10/03 05:14

ありがとうございます!modalViewの呼び出し元のViewControllerでmodalサイズを指定出来ないものと思い込みPresentationController側でUIPartsを指定していたので無駄に複雑になっていました。 margin指定のイニシャライザを拡張してやりたいことが実現出来ました! コンピューテッドプロパティの遅延実行も非常に勉強になりました。ありがとうございました。。
TsukubaDepot

2020/10/03 09:13

今気づいたのですが、lazy で指定できるのは格納型プロパティ(ストアドプロパティ、Stored property)だけですね。 https://docs.swift.org/swift-book/LanguageGuide/Properties.html >Lazy Stored Properties >A lazy stored property is a property whose initial value is not calculated until the first time it is used. You indicate a lazy stored property by writing the lazy modifier before its declaration.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問