見出し画像

「解いて学ぶ」SwiftによるiOSアプリ開発入門

はじめに

何となくわかった気になったけれど、実はわかってない、ということがよくあります。そこで、「解いて学ぶ」シリーズでは、問題を解いて学ぶことで物事を深く理解していきます。今回は、SwiftによるiOSアプリ開発入門です。
※協力:chatGPT(Model 4)

1. 問題編

【初級】
問題1: UITableViewを使った時、何のためにUITableViewDataSourceプロトコルを実装する必要がありますか?
選択肢:
A. テーブルビューの行数を設定する
B. セルのデザインを定義する
C. データを提供する
D. セルの高さを設定する

問題2: UIButtonのインスタンスがタップされたときに呼び出される関数を指定するプロパティは何ですか?
選択肢:
A. addTarget
B. didSelect
C. addGestureRecognizer
D. addTarget(for:)

問題3: Auto Layoutで制約を表すオブジェクトは何ですか?
選択肢:
A. NSLayoutConstraint
B. UIView
C. UIStackView
D. UIEdgeInsets

問題4: 画像を表示するためのUIコンポーネントは何ですか?
選択肢:
A. UIImageView
B. UILabel
C. UISwitch
D. UITextField

【中級】
問題5: Storyboardで作成したUIコンポーネントにアクセスするために使う変数に付ける属性は何ですか?

問題6: アプリがバックグラウンドに移動したときに呼び出される関数は何ですか?

問題7: UINavigationControllerのインスタンスで画面遷移を実行する関数は何ですか?

【上級】
問題8: マルチスレッディングを実装するためにGCDで使われるキューの種類は何ですか?

問題9: Core Dataを使ってデータを永続化する際に必要なステップは何ですか?

問題10: UIテストを行う際に使用されるフレームワークは何ですか?

2. 解説編

問題1:UITableViewDataSourceプロトコル

UITableViewを使った時、何のためにUITableViewDataSourceプロトコルを実装する必要がありますか?
解答: C. データを提供する
テーマ: UITableViewDataSourceプロトコル
解説: UITableViewDataSourceプロトコルは、テーブルビューに表示するデータを提供するために実装されます。具体的には、行数やセルの内容を設定するための関数が含まれます。
具体例(コード):

swiftCopy codeclass ViewController: UIViewController, UITableViewDataSource {
    @IBOutlet weak var tableView: UITableView!

    let data = ["Item 1", "Item 2", "Item 3"]

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.dataSource = self
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return data.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        cell.textLabel?.text = data[indexPath.row]
        return cell
    }
}

具体例の解説: 上記のコードでは、UITableViewDataSourceプロトコルを実装したViewControllerがテーブルビューのデータソースになっています。データの行数を決定するtableView(_:numberOfRowsInSection:)関数と、各行のセルを設定するtableView(_:cellForRowAt:)関数が実装されています。データソースとして、文字列の配列dataを使用しています。

問題2:UIButtonとアクション

UIButtonのインスタンスがタップされたときに呼び出される関数を指定するプロパティは何ですか?
解答: A. addTarget
テーマ: UIButtonとアクション
解説: UIButtonのインスタンスに対して、タップされたときに呼び出される関数を指定するには、addTargetメソッドを使用します。このメソッドには、対象のオブジェクト、アクション(セレクタ)、およびイベントタイプを指定します。
具体例(コード):

swiftCopy codeclass ViewController: UIViewController {
    @IBOutlet weak var button: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
        button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
    }

    @objc func buttonTapped() {
        print("Button tapped")
    }
}

具体例の解説: 上記のコードでは、buttonTapped関数がボタンがタップされたときに呼び出されるように設定されています。addTargetメソッドを使用して、ボタンのタップイベント(.touchUpInside)に対して、buttonTapped関数をアクションとして登録しています。

問題3:Auto Layoutと制約

Auto Layoutで制約を表すオブジェクトは何ですか?

解答: A. NSLayoutConstraint
テーマ: Auto Layoutと制約
解説: Auto Layoutでは、画面上のUIコンポーネントの位置やサイズを制約を使って指定します。制約を表すオブジェクトは、NSLayoutConstraintクラスです。このクラスを使って、UIコンポーネント間の関係を定義し、アプリのレイアウトを調整します。
具体例(コード):

swiftCopy codelet constraint = NSLayoutConstraint(item: viewA,
                                    attribute: .top,
                                    relatedBy: .equal,
                                    toItem: viewB,
                                    attribute: .bottom,
                                    multiplier: 1.0,
                                    constant: 20)

NSLayoutConstraint.activate([constraint])

具体例の解説: このコード例では、viewAの上辺とviewBの下辺の間に20ポイントの間隔を持つ制約を作成しています。NSLayoutConstraintのインスタンスを作成し、activate(_:)メソッドを使用して制約をアクティブにしています。

問題4:UIImageView

画像を表示するためのUIコンポーネントは何ですか?
解答: A. UIImageView
テーマ: UIImageView
解説: 画像を表示するためのUIコンポーネントはUIImageViewです。UIImageViewは、画像ファイルを表示するために使用されるUIViewのサブクラスです。画像は、UIImageオブジェクトとして読み込まれ、UIImageViewに割り当てられます。
具体例(コード):

swiftCopy codelet imageView = UIImageView()
let image = UIImage(named: "exampleImage")
imageView.image = image
imageView.contentMode = .scaleAspectFit

具体例の解説: このコード例では、UIImageViewのインスタンスを作成し、UIImageオブジェクトを読み込んで割り当てています。また、contentModeプロパティを使用して、画像の表示モードをアスペクト比を維持してフィットさせるように設定しています。

問題5:IBOutlet

Storyboardで作成したUIコンポーネントにアクセスするために使う変数に付ける属性は何ですか?
解答: @IBOutlet
テーマ: IBOutlet
解説: Storyboardで作成したUIコンポーネントにコードからアクセスするために、@IBOutlet属性を使って変数を宣言します。@IBOutlet属性を使用することで、Interface Builderとコードの間で接続が作成され、UIコンポーネントを操作できるようになります。
具体例(コード):

swiftCopy codeclass ViewController: UIViewController {
    @IBOutlet weak var label: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        label.text = "Hello, World!"
    }
}

具体例の解説: このコード例では、@IBOutlet属性を使用して、Storyboardで作成したUILabelにアクセスするための変数labelを宣言しています。viewDidLoad()関数内で、labelのテキストを変更しています。

問題6:アプリライフサイクル

アプリがバックグラウンドに移動したときに呼び出される関数は何ですか?
解答: applicationDidEnterBackground(_:)
テーマ: アプリライフサイクル
解説: アプリがバックグラウンドに移動したときに呼び出される関数は、UIApplicationDelegateプロトコルのapplicationDidEnterBackground(_:)関数です。この関数は、アプリがバックグラウンド状態に遷移する際にシステムから呼び出され、アプリの状態保存やリソース解放などの処理を実行することができます。
具体例(コード):

swiftCopy codeimport UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func applicationDidEnterBackground(_ application: UIApplication) {
        print("App moved to background")
    }
}

具体例の解説: このコード例では、UIApplicationDelegateプロトコルを実装したAppDelegateクラスで、applicationDidEnterBackground(_:)関数を定義しています。この関数が呼び出されると、コンソールに"App moved to background"というメッセージが出力されます。

問題7:UINavigationController

UINavigationControllerのインスタンスで画面遷移を実行する関数は何ですか?
解答: pushViewController(_:animated:)
テーマ: UINavigationController
解説: UINavigationControllerのインスタンスで画面遷移を実行するには、pushViewController(_:animated:)関数を使用します。この関数には、遷移先のビューコントローラとアニメーションを使用するかどうかを示すブール値を引数として渡します。
具体例(コード):

swiftCopy codeclass FirstViewController: UIViewController {
    @IBAction func moveToSecondView() {
        let secondViewController = SecondViewController()
        navigationController?.pushViewController(secondViewController, animated: true)
    }
}

具体例の解説: このコード例では、FirstViewControllerからSecondViewControllerに画面遷移する際に、pushViewController(_:animated:)関数を使用しています。moveToSecondView()関数が呼び出されると、SecondViewControllerのインスタンスが作成され、UINavigationControllerにプッシュされます。

問題8:GCD (Grand Central Dispatch)とマルチスレッディング

マルチスレッディングを実装するためにGCDで使われるキューの種類は何ですか?

解答: DispatchQueue
テーマ: GCD (Grand Central Dispatch)とマルチスレッディング
解説: GCD (Grand Central Dispatch)は、マルチスレッディングを実装するための技術で、キューを使用して非同期処理を実行します。キューの種類として、DispatchQueueがあります。DispatchQueueには、メインキュー、グローバルキュー、カスタムキューがあります。
具体例(コード):

swiftCopy codefunc performHeavyTask() {
    DispatchQueue.global(qos: .background).async {
        // Perform heavy task here

        DispatchQueue.main.async {
            // Update UI on the main thread
        }
    }
}

具体例の解説: このコード例では、重いタスクをバックグラウンドで実行し、完了後にメインスレッドでUIを更新するために、DispatchQueueを使用しています。まず、グローバルキューを使用して非同期に重いタスクを実行します。その後、メインキューにUI更新タスクをディスパッチして、メインスレッドで実行されるようにしています。

問題9:UITableViewとスクロール方向

UITableViewのスクロール方向を変更するために設定するプロパティは何ですか?
解答: UICollectionViewFlowLayoutのscrollDirection
テーマ: UITableViewとスクロール方向
解説: UITableViewのスクロール方向を変更するには、実際にはUICollectionViewとUICollectionViewFlowLayoutを使用します。UICollectionViewFlowLayoutのscrollDirectionプロパティを設定して、スクロール方向を制御します。
具体例(コード):

swiftCopy codelet layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)

具体例の解説: このコード例では、UICollectionViewFlowLayoutのインスタンスlayoutを作成し、scrollDirectionプロパティを水平方向に設定しています。その後、layoutを使用してUICollectionViewのインスタンスを作成しています。

問題10:プッシュ通知とデリゲート

アプリのプッシュ通知を受け取るために設定する必要があるプロトコルは何ですか?
解答: UNUserNotificationCenterDelegate
テーマ: プッシュ通知とデリゲート
解説: アプリのプッシュ通知を受け取るためには、UNUserNotificationCenterDelegateプロトコルを実装し、そのデリゲートを設定する必要があります。このデリゲートには、通知の表示方法や、通知がタップされたときの処理などが含まれています。
具体例(コード):

swiftCopy codeimport UserNotifications

class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        let center = UNUserNotificationCenter.current()
        center.delegate = self
        center.requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
            // Handle authorization result
        }
        return true
    }

    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        completionHandler([.alert, .sound, .badge])
    }
}

具体例の解説: このコード例では、AppDelegateクラスでUNUserNotificationCenterDelegateプロトコルを実装しています。application(_:didFinishLaunchingWithOptions:)関数内で、UNUserNotificationCenterのデリゲートを設定し、通知の権限をリクエストしています。さらに、userNotificationCenter(_:willPresent:withCompletionHandler:)関数を実装して、通知が表示される方法を定義しています。この場合、通知がアプリがフォアグラウンドにあるときもアラート、サウンド、バッジの形で表示されます。

3. テーマ学習編

3.1. UITableViewDataSourceプロトコル

定義: UITableViewDataSourceプロトコルは、UITableViewのデータを提供するために必要なメソッドが定義されたプロトコルです。

具体例: テーブルビューで表示するセルの数や内容を提供するために、以下のメソッドを実装します。

  • tableView(_:numberOfRowsInSection:)

  • tableView(_:cellForRowAt:)

コード:

swiftCopy codeclass MyTableViewController: UITableViewController, UITableViewDataSource {
    let data = ["Apple", "Banana", "Orange"]

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.dataSource = self
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return data.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
        cell.textLabel?.text = data[indexPath.row]
        return cell
    }
}

コードの解説: このコード例では、MyTableViewControllerがUITableViewDataSourceプロトコルを実装しています。データソースメソッドを使って、テーブルビューに表示するセルの数と内容を提供しています。

3.2. UIButtonとアクション

定義: UIButtonは、ユーザーがタップすることでアクションを実行するUIコンポーネントです。アクションは、コード内の関数として定義され、ボタンがタップされたときに呼び出されます。
具体例: ボタンがタップされたときに、メッセージを表示する処理を実装する。
コード:

swiftCopy codeclass ViewController: UIViewController {
    @IBAction func buttonTapped(_ sender: UIButton) {
        print("Button tapped!")
    }
}

コードの解説: このコード例では、ボタンがタップされたときに呼び出されるbuttonTapped(_:)関数が定義されています。ボタンがタップされると、コンソールに"Button tapped!"というメッセージが出力されます。

3.3.Auto Layoutと制約

定義: Auto Layoutは、アプリの画面上でUI要素のサイズと位置を動的に調整するためのシステムです。制約は、Auto Layoutによって適用されるルールで、UI要素のサイズや位置の関係を定義します。

具体例: UILabelを画面の中央に配置する制約を設定する。

コード:

swiftCopy codeclass ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        let label = UILabel()
        label.text = "Hello, world!"
        label.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(label)

        NSLayoutConstraint.activate([
            label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            label.centerYAnchor.constraint(equalTo: view.centerYAnchor)
        ])
    }
}

コードの解説: このコード例では、UILabelを画面の中央に配置するための制約を設定しています。まず、UILabelのインスタンスを作成し、translatesAutoresizingMaskIntoConstraintsプロパティをfalseに設定してAuto Layoutを使用することを明示しています。次に、NSLayoutConstraint.activateメソッドを使って、画面の中央に配置するための制約を設定しています。

3.4. UIImageView

定義: UIImageViewは、画像を表示するためのUIコンポーネントです。UIImageオブジェクトを使用して、表示する画像を指定します。
具体例: プロジェクト内の画像ファイル「sample.png」を画面に表示する。
コード:

swiftCopy codeclass ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        let imageView = UIImageView(image: UIImage(named: "sample.png"))
        imageView.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
        view.addSubview(imageView)
    }
}

コードの解説: このコード例では、UIImageViewのインスタンスを作成し、UIImage(named:)イニシャライザを使って表示する画像を指定しています。その後、frameプロパティを設定して画像の位置とサイズを指定し、ビューに追加しています。

3.5. IBOutlet

定義: IBOutletは、Interface Builderで作成されたUIコンポーネントとコードを接続するためのプロパティです。これにより、コードからUIコンポーネントのプロパティを設定したり、アクションを実行したりすることができます。

具体例: Interface Builderで配置したUILabelをコードから参照する。

コード:

swiftCopy codeclass ViewController: UIViewController {
    @IBOutlet weak var label: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        label.text = "Hello, IBOutlet!"
    }
}

コードの解説: このコード例では、IBOutletプロパティlabelを使用して、Interface Builderで配置したUILabelをコードから参照しています。viewDidLoad()メソッド内で、UILabelのtextプロパティに値を設定しています。

3.6. アプリライフサイクル

定義: アプリライフサイクルは、アプリが起動から終了までの間に通るさまざまな状態のことです。UIApplicationDelegateプロトコルのメソッドを通じて、アプリの状態の変化に対応した処理を実行することができます。

具体例: アプリがアクティブになったときにコンソールにメッセージを出力する。

コード:

swiftCopy codeclass AppDelegate: UIResponder, UIApplicationDelegate {
    func applicationDidBecomeActive(_ application: UIApplication) {
        print("App is now active.")
    }
}

コードの解説: このコード例では、UIApplicationDelegateプロトコルのメソッド`applicationDidBecomeActive(_:)`を実装しています。アプリがアクティブになったとき、このメソッドが呼び出され、コンソールに"App is now active."というメッセージが出力されます。

3.7. UINavigationController

定義: UINavigationControllerは、階層的な画面遷移を管理するためのコンテナビューコントローラです。画面遷移の履歴がスタックとして保持され、バックボタンを使って前の画面に戻ることができます。

具体例: 画面遷移を実現するために、UINavigationControllerを使ってビューコントローラをプッシュする。

コード:

swiftCopy codeclass ViewController: UIViewController {
    @IBAction func nextButtonTapped(_ sender: UIButton) {
        let secondViewController = SecondViewController()
        navigationController?.pushViewController(secondViewController, animated: true)
    }
}

コードの解説: このコード例では、ボタンがタップされたときに、UINavigationControllerを使って新しいビューコントローラ(SecondViewController)をプッシュして画面遷移を実現しています。

3.8. GCD (Grand Central Dispatch)とマルチスレッディング

定義: GCDは、マルチコアプロセッサを効率的に利用するための並列処理ライブラリです。GCDを使って、複数の処理を並行して実行したり、非同期処理を行ったりすることができます。

具体例: GCDを使って、非同期にデータを取得し、その後UIを更新する。

コード:

swiftCopy codeclass ViewController: UIViewController {
    @IBOutlet weak var label: UILabel!

    @IBAction func fetchDataButtonTapped(_ sender: UIButton) {
        DispatchQueue.global(qos: .background).async {
            let data = self.fetchData()
            DispatchQueue.main.async {
                self.label.text = "Fetched data: \(data)"
            }
        }
    }

    func fetchData() -> String {
        // Simulate fetching data from the server
        Thread.sleep(forTimeInterval: 2)
        return "Sample data"
    }
}

コードの解説: このコード例では、GCDを使って非同期にデータを取得しています。グローバルキューでデータ取得処理を行い、その後メインキューでUIを更新しています。

3.9. UITableViewとスクロール方向

定義: UITableViewは、リスト形式でデータを表示するためのUIコンポーネントです。デフォルトでは、縦方向にスクロールすることができます。ただし、UICollectionViewを使用することで、縦方向だけでなく横方向にもスクロールするリストを作成することができます。

具体例: データの配列を使って、UITableViewで縦方向にスクロールするリストを表示する。

コード:

swiftCopy codeclass MyTableViewController: UITableViewController {
    let data = ["Apple", "Banana", "Orange"]

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return data.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
        cell.textLabel?.text = data[indexPath.row]
        return cell
    }
}

コードの解説: このコード例では、MyTableViewControllerがUITableViewDataSourceプロトコルを実装しています。データソースメソッドを使って、テーブルビューに表示するセルの数と内容を提供しています。UITableViewはデフォルトで縦方向にスクロールしますが、横方向のスクロールが必要な場合はUICollectionViewを利用できます。

3.10. プッシュ通知とデリゲート

定義: プッシュ通知は、アプリがバックグラウンドにある場合や完全に終了している場合でも、リモートサーバーからユーザーに通知を送信する仕組みです。デリゲートは、プッシュ通知を受け取った際の処理を行うために使用されるプロトコルです。

具体例: プッシュ通知を受け取った際に、アプリ内で特定の画面を表示する。

コード:

swiftCopy codeimport UIKit
import UserNotifications

class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        let center = UNUserNotificationCenter.current()
        center.delegate = self
        center.requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
            // Handle authorization
        }
        return true
    }

    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        if let window = UIApplication.shared.windows.first {
            let storyboard = UIStoryboard(name: "Main", bundle: nil)
            let notificationViewController = storyboard.instantiateViewController(withIdentifier: "NotificationViewController")
            window.rootViewController = notificationViewController
            window.makeKeyAndVisible()
        }
        completionHandler()
    }
}

コードの解説: このコード例では、UNUserNotificationCenterDelegateプロトコルを実装して、プッシュ通知を受け取った際の処理を行っています。まず、application(_:didFinishLaunchingWithOptions:)メソッド内で、プッシュ通知の許可をリクエストしています。その後、デリゲートメソッドuserNotificationCenter(_:didReceive:withCompletionHandler:)を実装して、プッシュ通知を受け取ったときの処理を定義しています。この例では、通知を受け取るとアプリ内で特定の画面(NotificationViewController)を表示しています。最後に、completionHandler()を呼び出して、通知の処理が完了したことをシステムに伝えています。


この記事が気に入ったらサポートをしてみませんか?