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

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

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

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

Swift

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

解決済

アラートを表示するクラスを作成したい

muaik
muaik

総合スコア4

Xcode

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

Swift

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

1回答

0評価

1クリップ

4930閲覧

投稿2020/10/15 15:12

前提・実装したいこと

Xcodeで簡単なカードゲームアプリを作っているのですが、全ての画面にタイトルへ戻るボタンを表示しています。

ボタンを押してタイトルに戻る際には一度アラートを表示させてから画面遷移が行うようにしたいと思い、アラートを表示して画面遷移する関数を作成したのですが、タイトル画面以外全ての画面に実装するため、できれば別ファイルを作成し、一つのクラスにまとめて毎回書かなくてもいいようにしたいと思っています。

そこでTitleBackBtnというクラスを作ったのですが、エラーが発生し、うまく動作しません。

コード中盤の
self.present(vc, animated: true, completion: nil)
に「Value of type 'TitleBackBtn' has no member 'present'」というエラーが

最後の行の
present(alert, animated: true, completion: nil)
に「cannot find 'present' in scope」というエラーが出ています。

それぞれの画面のViewControllerの中に関数を書いた場合は動作するため、エラーメッセージからおそらくViewControllerの指定の仕方がselfではないのだとは思うのですが、自身では解決方法が見つかりませんでした。
Swift初心者用の書籍を1冊読み終えたばかりで、エラーが発生しているコード以前にクラス作りの基本的な部分が抜けている可能性もあり、大変申し訳ないのですが、解決方法をご存知の方がいらっしゃればご教授いただけると幸いです。

該当のソースコード

Swift

import Foundation import UIKit class TitleBackBtn{ //アラートボタン func titleAlert(){ //アラートボタンのタイトルと本文の表示 let alert: UIAlertController = UIAlertController(title: "タイトルへ戻る", message: "タイトル画面へ戻ってもよろしいですか?", preferredStyle: UIAlertController.Style.alert) //OKボタンの表示と押された時の処理 let defaultAction: UIAlertAction = UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler:{ //OKボタンが押された時の処理 (action: UIAlertAction!) -> Void in print("OK") let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil) let vc = storyboard.instantiateViewController(withIdentifier: "titleView") as! ViewController self.present(vc, animated: true, completion: nil) }) //キャンセルボタンの表示と押された時の処理 let cancelAction: UIAlertAction = UIAlertAction(title: "キャンセル", style: UIAlertAction.Style.cancel, handler:{ //キャンセルボタンが押された時の処理 (action: UIAlertAction!) -> Void in print("Cancel") }) //UIAlertControllerにActionを追加 alert.addAction(cancelAction) alert.addAction(defaultAction) //Alertを表示 present(alert, animated: true, completion: nil) } }

良い質問の評価を上げる

以下のような質問は評価を上げましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

  • プログラミングに関係のない質問
  • やってほしいことだけを記載した丸投げの質問
  • 問題・課題が含まれていない質問
  • 意図的に内容が抹消された質問
  • 過去に投稿した質問と同じ内容の質問
  • 広告と受け取られるような投稿

評価を下げると、トップページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

TsukubaDepot

2020/10/16 07:35

このコードだと、タイトルに戻るたびに新しい View Controller を作ってしまいますが、それについては認識されていますでしょうか。 つまり、見た目は「元の画面」に戻ったように見えても、それは戻ったのではなく「元の画面と同じ画面」を「新しく」表示しているコードになっています。このコードのまま、次々に元の画面を新規作成してしまうと、そのうちメモリ不足で落ちてしまいます。 一般的な書き方であれば、遷移元に戻るのであれば dismiss(animated:completion:) を使って現在の画面を破棄するのですが、参考にされた本にはそのことについて言及されていないでしょうか。
muaik

2020/10/16 10:21

構造上の問題を教えていただきありがとうございます。 お恥ずかしながら、ご指摘いただくまで画面が破棄されずに重なり続けてしまう状態であることは認識していませんでした。今回の画面遷移については詳しい記載が本になかったため、ネットにあったコードを参考にしたものです。 dismissの使い方を調べコードを修正し、現在の画面を破棄することはできました。 1つ前の画面には戻るのですが、2つ前、3つ前の画面に戻れず新たな問題が発生しています。 これも初歩的な問題だと思うので恐縮ですが、2つ3つと重なることを防ぐためタイトル画面以外は、画面遷移する際に遷移元の画面を破棄しつつ遷移したいのですが、そのような方法はあるのでしょうか?
TsukubaDepot

2020/10/16 10:33

全体的な構造や実現されたい内容を拝見しないことには何とも言えない部分はありますが、たとえば Navigation Controllerを使っていれば、任意の画面に戻ることは割合簡単にできますし、present/dismiss を使った方法でも、やれないことはないかと思います。 遷移前の画面を破棄する方法は基本的にないと思います。というのは、遷移先となる View Controller のインスタンス(子)は遷移元が親となっているためです。依存関係があるため、子よりも親を先に破棄することはできず、別の方法を考える必要があるかと思います。 もしかしたら、画面遷移の関係を整理すると、もっと簡単に解決できるかもしれません。
TsukubaDepot

2020/10/16 10:34

もし差し支えなければ、参考にされている書籍名を教えていただけないでしょうか。 同じ本が手元にあれば、参考になる部分をご提示できるかもしれません。
muaik

2020/10/16 11:13

ご丁寧に回答いただきありがとうございます。 書籍については「たった2日でマスターできるiPhoneアプリ開発集中講座」を読み、参考しています。 また「絶対に挫折しないiPhoneアプリ開発「超」入門 第8版」も持っています。こちらはSwiftUIの使い方を解説していたためあまり読み進めていない状態です。 現在、人狼ゲームのようなカードゲームアプリを作っており画面は、 タイトル画面→プレイヤー名入力画面→プレイヤーが配られた役職カードを確認する画面→話し合いのタイマー画面・・・ といった遷移をしていくような構造になっているのですが、最初のご指摘を受けて、このまま作り続けると延々と画面が積み重なっていってしまうような気がしています。 「NavigationControllerを使っていれば・・・」とアドバイスをいただき少し調べて見て、そちらの方が良さそうだとは思ったのですが、使った場合に全体がどのような構造になるのかがイメージできず、またそのやり方もぼんやりとしかまだわかっていません。 最初の質問から本題が離れてしまい申し訳ないのですが、NavigationControllerを使うと、画面は重ならず、遷移したい画面に移って行けるということでしょうか?
TsukubaDepot

2020/10/16 12:28

「たった2日で〜」は第3版しかもっていませんが、 P.344に「ナビゲーションコントローラとナビゲーションバー」という形で、NavigationController の説明が書いてありました。 iOS 標準の「設定」アプリのように、一つ項目を選ぶごとに次々に関連した View Controller を表示させる方式です(ドリルダウン)。 https://qiita.com/usagimaru/items/9b55daa4d88b0bb98f38#%E3%83%97%E3%83%83%E3%82%B7%E3%83%A5%E9%9A%8E%E5%B1%A4%E5%9E%8B この方法も、これまでに表示した view Controller を表示していることには変わりませんが、積み重ねた View Controller のうち、任意の View Controller に戻ることが容易なため、いきなり数階層もどるような場合には便利かと思います。また、一つ前の画面に戻る操作は自動で組み込まれるため(非表示にもできる)、画面遷移の管理が楽という利点もあります。 一方、presetで View Controller を表示する方法は、上に示したリンクのうち、モーダル(分岐型)と呼ばれている方法です。こちらも階層を重ねていくことには違いありませんが、Navigation Controller と違い、複数の View Controller を集約して管理しているわけではないので、全て自分の責任で管理する必要があります。 実は、画面遷移は UI 的に考えても難しい側面があるのですが、一番良いのは iOS 標準アプリや、よく使われているアプリを使い込み、それらの画面遷移がどのようになっているかよく観察することかと思います。実際には Navigation Controller だけ、独自に View Controller を present するだけ、ということは少なく、両方を組み合わせて使っている例が多いかと思います。 あまりまとまりがなくて申し訳ないのですが、どちらにしても画面遷移の関係をよく考え、新しく作る View Controller を最小限にする(使い回す)ような構造にするのが良いのではないかと思います。
muaik

2020/10/16 14:42

画面遷移について詳しく解説していただき、イメージしづらかった部分が理解できてきました。 質問のこと以前に書籍を復習し(自分の持っている版にも記載がありました!)もう少し全体の設計や画面遷移について勉強し改めて取り組んでみようと思います。 脱線してしまった質問に丁寧なご回答をいただき本当にありがとうございました。
TsukubaDepot

2020/10/16 14:46

追記は脇道にそれてしまったので、ご質問への回答は回答の方に記載しました。 ただ、これでどれだけ記述量が減るのか難しいところなのですが(汎用性を持たせようとすればするほどむしろ煩雑になる)、参考になればと思います。

まだ回答がついていません

会員登録して回答してみよう

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

ただいまの回答率
87.20%

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

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

質問する

関連した質問

同じタグがついた質問を見る

Xcode

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

Swift

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