20210117のSwiftに関する記事は9件です。

Swift チャットアプリのチャット画面が作りたい!

チャットアプリのチャット画面に必要なもの

コロナ禍の中なかなか就職が決まらず暇なので、チャットアプリのチャット画面を作り方を記事にしたいと思います。
チャット画面に最低限必要なものってなんだと思いますか?
今回は僕が勝手に思うチャット画面に最低限必要なもので実装していきます。
必要なコンポーネントは以下

tableView: メッセージを一覧表示するのに使います。
MessageCell: プロフィールとかメッセージをまとめます。
profileImageView: プロフィール画像を表示をします。
messageLabel: メッセージの表示をします。

他にも送信時間表示用のlabelとかは?と思われると思いますが、データベースとか使って実際にメッセージの送受信をするわけではないので今回はこれだけにします。

実装

まずはViewControllerの方から

class ViewController: UIViewController {

    private let tableView = UITableView()

    //メッセージを格納する用の配列
    private var messages = [String]()

    override func viewDidLoad() {
        super.viewDidLoad()
        initTableView()
        initMessages()
        view.addSubview(tableView)
    }

    //tableViewの設定
    private func initTableView() {
        tableView.tableFooterView = UIView()
        tableView.separatorStyle = .none
        tableView.register(MessageCell.self, forCellReuseIdentifier: MessageCell.id)
        tableView.delegate = self
        tableView.dataSource = self
        tableView.frame = view.bounds
    }

    //messagesにメッセージを追加
    private func initMessages() {
        messages.append("こんにちは")
        messages.append("今日の12時ごろ予定空いてますか?")
        messages.append("ひまですね")
        messages.append("寿限無(じゅげむ) 寿限無(じゅげむ) 五劫(ごこう)のすりきれ 海砂利(かいじゃり)水魚(すいぎょ)の水行末(すいぎょうまつ) 雲来末(うんらいまつ) 風来末(ふうらいまつ) 食(く)う寝(ね)るところに 住(す)むところ やぶらこうじの ぶらこうじ パイポ パイポ パイポの シューリンガン シューリンガンの グーリンダイ グーリンダイの ポンポコピーのポンポコナの 長久命(ちょうきゅうめい)の長助(ちょうすけ)")
    }

}

extension ViewController: UITableViewDelegate, UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return messages.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: MessageCell.id, for: indexPath) as! MessageCell
        cell.message = messages[indexPath.row]
        return cell
    }
}

initTableView()の中を見ていきましょう。
tableFooterView = UIView()は要素数以上の時に表示される空のcellを消すためです。
separatorStyle = .noneはcellとcellの間の薄い灰色のボーダー線を消します。
registerはカスタムセルを表示するためです。
こちらを参照してください。
コードでカスタムセルを使う時register(_:forCellReuseIdentifier:)関数を入れそびれていた
ViewControllerの中についての説明はこれくらいですかね。

次はカスタムセルを作っていきます。

Message.swift
class MessageCell: UITableViewCell {

    static let id = "MessageCell"

    public var message: String? {
        didSet {
            messageLabel.text = message
        }
    }

    private let profileImageView: UIImageView = {
        let imageView = UIImageView()
        imageView.image = #imageLiteral(resourceName: "image.jpeg")
        imageView.layer.masksToBounds = true
        imageView.layer.cornerRadius = 25
        return imageView
    }()
    private let backView: UIView = {
        let view = UIView()
        view.backgroundColor = .opaqueSeparator
        view.layer.cornerRadius = 20
        view.layer.masksToBounds = true
        return view
    }()
    private let messageLabel: UILabel = {
        let label = UILabel()
        label.font = .systemFont(ofSize: 16)
        // labelの行数を指定
        label.numberOfLines = 0
        return label
    }()

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)

        addSubview(profileImageView)
        addSubview(backView)
        backView.addSubview(messageLabel)

        setupAutoLayout()
    }

    private func setupAutoLayout() {
        profileImageView.translatesAutoresizingMaskIntoConstraints = false
        backView.translatesAutoresizingMaskIntoConstraints = false
        messageLabel.translatesAutoresizingMaskIntoConstraints = false

        let constraints = [
            profileImageView.topAnchor.constraint(equalTo: topAnchor, constant: 10),
            profileImageView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 10),
//            profileImageView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -10),
            profileImageView.widthAnchor.constraint(equalToConstant: 50),
            profileImageView.heightAnchor.constraint(equalToConstant: 50),

            backView.topAnchor.constraint(equalTo: profileImageView.topAnchor),
            backView.leadingAnchor.constraint(equalTo: profileImageView.trailingAnchor, constant: 5),
            backView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -10),
            backView.widthAnchor.constraint(lessThanOrEqualToConstant: 250),

            messageLabel.topAnchor.constraint(equalTo: backView.topAnchor, constant: 8),
            messageLabel.leadingAnchor.constraint(equalTo: backView.leadingAnchor, constant: 8),
            messageLabel.bottomAnchor.constraint(equalTo: backView.bottomAnchor, constant: -8),
            messageLabel.trailingAnchor.constraint(equalTo: backView.trailingAnchor, constant: -8),
        ]

        NSLayoutConstraint.activate(constraints)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

profileImageViewbackViewmessageLabelの宣言をしています。
クロージャでまとめるといいですね。
backViewmessageLabelに直接背景色を指定してしまうと背景と文字の間に余白がなくなって見ずらいのでいい感じに余白を作るために使います。
setupAutoLayoutの中を見ていきましょう。
viewtranslatesAutoresizingMaskIntoConstraints = falseという記述があります。
これをしないとautolayoutが使えないことがあるらしいです。
Auto Layoutをコードから使おう
constraintsからはautoLayoutでレイアウトを設定しています。
配列でまとめているのでNSLayoutConstraint.activate()でまとめて有効にできます。
一部分だけ変更したい場合は

[viewの変数名].topAnchor.constraint(equalTo: topAnchor).isActive = true

でできます。

ビルドしてみましょう。
Simulator Screen Shot - iPhone 11 - 2021-01-17 at 22.33.44.png
いい感じに表示できてますね。

まとめ

今回は相手側だけになりましたが制約を変更すれば自分の方も作れます。
もっと簡単にできる方法があれば教えてください。
わざわざ自分で実装するのめんどくさいという方はMessageKitを調べてみてください。

冒頭でも言ったように就職先募集してます。
あー、優しい企業様就職先をください!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Swift】Hello Swift!と表示させる

はじめに

現在、書籍を使ってSWiftの勉強をしています。
備忘録として記事を書きます。

Labelを配置

①project navigatorからファイルの一覧表示
②Main.storyboardを選択
③View Controller Scene▼
  View Controller▼
    Viewを選択
④Libraryをクリック
 Library画面がポップアップで表示される。
⑤検索窓にLabelと入力する

⑥検索されたLabelをstoryboardの中央にドラッグ&ドロップ

オートレイアウトを設定

①配置したLabelをクリック
②Xcode右下にあるAlignをクリック
③[Horizontally in Container]と[Vertically in Container]にチェックを入れる。
[Horizontally in Container]で画面中央から水平方向の距離を入力。
 ⇨[0]であれば、左右の中央に配置される。
[Vertically in Container]で画面中央から垂直方向の距離を入力
 ⇨[0]であれば、上下の中央に配置される。

④[Add 2 constraints]をクリックして、制約を反映。

Labelとプログラムの関連付け

①Main.storyboardを選択、エディタの表示
②Labelからエディタへドラッグ&ドロップ
 ⇨Labelの上にマウスポインタを置いた状態で、「control」キー+クリックを押しながら、右方向へドラッグ(引っ張ると青いラインが出る)。エディタの最後にある中括弧のすぐ上までラインを伸ばす。
③関連付けの設定を行うためのダイアログが表示される。この画面にて、Labelとプログラムをどのような名前で関連付けるかを設定。

④[connect]をクリックすると↓のようにコードが追加されます。これがLabelとの関連付けを示すコードになる。

@IBOutlet weak var outputLabel: UILabel!

Labelに文字をセットするコードを書く
class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        outputLabel.text = "Hello Swift!"
    }

    @IBOutlet weak var outputLabel: UILabel!
}

以上です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

FireStoreでサブコレクションを追加 [Swift]

サブコレクションとは、ドキュメント内のコレクションのことです。
これを新しく追加するには、ドキュメント内のサブコレクション内のドキュメントを作ることで、自動で生成されます。

たとえば、国コレクション内に”japan”というドキュメントがある場合、

let db = Firestore.firestore()
db.collection("countries")
            .document("japan")
            .collection("prefectures") // サブコレクションであるprefecturesがない場合、自動でリストが生成される。
            .document("osaka")
            .setData([
    capital: "osaka",
    specialty: "takoyaki"
]) { err in
    if let err = err {
        print("Error writing document: \(err)")
    } else {
        print("Document successfully written!")
    }
}

これでjapanドキュメントの中にprefecturesが生成され、県庁所在地と名物の情報をもったosakaというドキュメントが追加されます。

セキュリティルールの追加をお忘れなく。

?


フリーランスエンジニアです。
お仕事のご相談こちらまで
rockyshikoku@gmail.com

Core MLを使ったアプリを作っています。
機械学習関連の情報を発信しています。

Twitter
Medium

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SceneEditorから追加したSCNActionに、コードからアクセスする

SCNActionはコードからもしくはSceneEditorから追加できます。
SceneEditorから追加する方法はApple Engineさんの以下の記事がわかりやすいかと思います。

iOS で SceneKit を試す(Swift 3) その15 - Scene Editor の Action Editor を使ってみる

SceneEditorで追加したアクションをコードからリピートしたり組み合わせたりしたい時に。

ノードがアクションを持っているかどうかの確認

node.hasActions

ノードが持っているアクションのKeyの確認

SceneEditorからアクションを追加した場合、英数字の文字列がデフォルトで割り当てられます。

node.actionKeys

アクションの取得

たとえば、ノードに割り当てられているアクションの最初のものを取得するには以下

let actionFromNode = node.action(forKey: node.actionKeys[0])

取得したアクションは、SCNActionとして再利用できる

anotherNode.runAction(actionFromNode)

?


フリーランスエンジニアです。
お仕事のご相談こちらまで
rockyshikoku@gmail.com

Core MLを使ったアプリを作っています。
機械学習関連の情報を発信しています。

Twitter
Medium

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Swift UIScrollViewの使い方

UIScrollViewをコードで実装

独学でアプリ制作しているんですけど、そういえばscrollView使ったことないなと思ったので勉強しました!
まず、全く調べずにscrollViewを使ってみようとしました。
そのコードがこちら

class ViewController: UIViewController {

    private let label = UILabel()

    override func viewDidLoad() {
        super.viewDidLoad()

        let scrollView = UIScrollView()

        scrollView.frame = .init(x: 0, y: 0, 
            width: view.frame.size.width, height: view.frame.size.height)

        view.addSubview(scrollView)
        scrollView.addSubview(label)

        label.text = "hello world"
        label.frame = .init(x: 0, y: 0, width: 100, height: 50)
        label.center = scrollView.center
    }

}

結果はスクロールできませんでした。
labelscrollViewがちゃんと表示されているか確認するために追加しています。

なんで!?と思い調べてみるとcontentSizeというものを指定しないといけないらしい。
contentSizeはスクロール領域を決めるらしい。
ということで修正したものがこちら

class ViewController: UIViewController {

    private let label = UILabel()

    override func viewDidLoad() {
        super.viewDidLoad()

        let scrollView = UIScrollView()

        //scrollViewの大きさを設定。
        scrollView.frame = .init(x: 0, y: 0, 
            width: view.frame.size.width * 2, height: view.frame.size.height * 2)

        //スクロール領域の設定
        scrollView.contentSize = CGSize(width:view.frame.size.width * 2, height:view.frame.size.height * 2)

        //scrollViewをviewのSubViewとして追加
        view.addSubview(scrollView)
        scrollView.addSubview(label)

        label.text = "hello world"
        label.frame = .init(x: 0, y: 0, width: 100, height: 50)
        label.center = scrollView.center
    }

}

これでどうだ!と思いビルドしましたがスクロールできませんでした。

さらに調べると、framecontentSizeより小さくないといけないみたい。

class ViewController: UIViewController {

    private let label = UILabel()

    override func viewDidLoad() {
        super.viewDidLoad()

        let scrollView = UIScrollView()

        //scrollViewの大きさを設定。
        scrollView.frame = .init(x: 0, y: 0, 
            width: view.frame.size.width, height: view.frame.size.height)

        //スクロール領域の設定
        scrollView.contentSize = CGSize(width:view.frame.size.width * 2, height:view.frame.size.height * 2)

        //scrollViewをviewのSubViewとして追加
        view.addSubview(scrollView)
        scrollView.addSubview(label)

        label.text = "hello world"
        label.frame = .init(x: 0, y: 0, width: 100, height: 50)
        label.center = scrollView.center
    }

}

結果は...いけたーーーー!!!

まとめ

UIScrollViewを使うときは

contentSizeを指定しないといけない
contentSizeframeより大きくないといけない

ということに注意して実装しましょう!

引用

[Swift4]スクロールビューの使い方

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Swift]アプリアイコンの設定をしたのに反映されない時の対処法

困っていたこと

a
このようにAppIconにアイコンを設定したのに、いざシミュレーターや実機テストで確認してみると、アイコン画像が初期画像のまま変わっていない時の解決策について
調べて出てきた再起動、アプリを削除して再インストール、Clean Build Folderをしても解決できませんでした。

解決した方法

b
Assets.xcassetsをクリック→AppIconをクリックし、
c
この画像のTarget Membershipの一番上の部分にチェックを入れると、変更されます。
ここのチェックが外れると、初期画像になってしまうようです。

最後に

同じような事例で、他の解決方法、ご指摘などあれば気軽にコメントお願いします!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Swift] Realmを実装して分かったこと色々

はじめに

Realmを以下の記事を参考に実装しました。
https://qiita.com/pe-ta/items/616e0dbd364179ca284b
以下のリンクから動き確認できます。
https://twitter.com/vex3ex5frd2xcvg/status/1350637210106699777?s=21
そこから色々調べてみたので、自分なりに理解した事を書いてみようと思います。
実装の手順などは、以下の記事から確認してください。

実装

① importする

まずはRealmSwiftをimportします。
RealmSwiftが必要な箇所でそれぞれimportしてみてください。
はじめはエラーになりますので、1度ビルドする事でimport出来ます。

ViewController.swift
import UIKit
// RealmSwiftをimportするとエラーになるが、ビルドしたら治る
import RealmSwift

② モデルクラスの作成

ファイルの追加でswiftファイルを作成してください。
このファイルでは、Realmで扱うデータの項目とその型を定義します。
要は、このプロパティに値を保存していくイメージになります。
Realmモデルのプロパティには@objcdynamicをつける必要があります。

TodoModel.swift
import Foundation
import RealmSwift

class TodoModel: Object {
    @objc dynamic var koumoku: String? = nil
}

③ viewControllerに変数を用意

Resultsは「オブジェクトから返される Realm の自動更新コンテナ型」だそうです。
この変数にデータを追加していくことになります。

ViewController.swift
    // 作成したTodoModel型の変数を用意。
    // Realmから受け取るデータを入れる変数
    var itemList: Results<TodoModel>!

④ viewDidLoadでインスタンス化

今回使用するRealmをインスタンス化して使えるようにします。
次に、object()を使用します。これは()内に指定したデータを全て取得できるものなので、
取得を行い、取得したデータを③で作成した変数に入れます。

ViewController.swift
override func viewDidLoad() {
        super.viewDidLoad()

        // Realmをインスタンス化する
        let realm = try! Realm()

        // objects()はRealmに保存されている指定されたデータを全て取得する!
        // object().filter()でさらにフィルタリングして指定することもできるそうです。
        self.itemList = realm.objects(TodoModel.self)
    }

⑤ データを追加して保存していく

今回はbuttonを押したらtextFieldに書いた内容が追加されるようにします。
追加・保存を行いたいAction内で書いてみてください。

1.追加していく場所は、②で作成したモデルクラス内のプロパティになりますので、モデルクラスをインスタンス化していきます。
2.textField.textを②で作成したkoumokuプロパティに入れます。
3.buttonAction内でもRealmを使うので、viewDidLoad内で作成したように、Realmをインスタンス化します。
4.realm.writeはRealmインスタンスを最新版に更新し、該当する場合は通知を作成すると公式ドキュメントにありました。
2でデータを更新しているので、realm.writeで最新のものを取得しているわけです。
realm.add()は管理されていないオブジェクトを()内のRealmに追加します。
つまり、realm.add()で管理されてない(追加したデータ)をRealmに追加して、
realm.writeでその最新バージョンを取得しているわけです。

ViewController.swift
    @IBAction func addButton(_ sender: Any) {
        // 1.モデルクラスをインスタンス化。これでアクセスできるようになる!
        let instanceTodoModel: TodoModel = TodoModel()
        // 2.textFieldの値をぶち込む
        instanceTodoModel.koumoku = self.textField.text

        // 3.Realmをインスタンス化してデータベースを取得!viewDidLoadでも行ったやつ
        let realm = try! Realm()

        // 4.textFieldの値をデータベースに追加する
        // write は refresh() が呼び出されたかのように Realm インスタンスを最新の Realm バージョンに更新し、該当する場合は通知を生成します。
        try! realm.write {
            realm.add(instanceTodoModel)
        }
        self.tableView.reloadData()
    }

⑥ TableViewの実装

itemListにRealmから受け取ったデータが入っているので、それを使用してTableViewCellを作成していきます。

ViewController.swift
extension ViewController: UITableViewDataSource {

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

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell1", for: indexPath)

        let item: TodoModel = self.itemList[indexPath.row]

        cell.textLabel?.text = item.koumoku

        return cell
    }

⑦ 削除機能

Viewcontroller.swift
    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
        // この中でもRealmを使えるようにインスタンス化
        let realm = try! Realm()

        if editingStyle == .delete {
            // 削除したいデータを検索する。今回はdeleteしたいcellのindexpath.row番目の項目を削除したいので、それをobjectで指定。
            let deleteItem = realm.objects(TodoModel.self)[indexPath.row]

            do{
                // write は refresh() が呼び出されたかのように Realm インスタンスを最新の Realm バージョンに更新し、該当する場合は通知を生成します。
                try realm.write{
                    // 追加の時のaddの削除版
                    realm.delete(deleteItem)
                }
            }catch{
                    print("Error")
                }
            }
        tableView.reloadData()

        }

実際のコード

ViewController.swift
import UIKit
// RealmSwiftをimportするとエラーになるが、ビルドしたら治る
import RealmSwift

class ViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet weak var textField: UITextField!
    @IBOutlet weak var tableView: UITableView!

    // 作成したTodoModel型の変数を用意。
    // Realmから受け取るデータを入れる変数
    var itemList: Results<TodoModel>!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Realmをインスタンス化する
        let realm = try! Realm()

        // objects()はRealmに保存されている指定されたデータを全て取得する!
        self.itemList = realm.objects(TodoModel.self)
    }

    @IBAction func addButton(_ sender: Any) {
        // モデルクラスをインスタンス化。これでアクセスできるようになる!
        let instanceTodoModel: TodoModel = TodoModel()
        // textFieldの値をぶち込む
        instanceTodoModel.koumoku = self.textField.text

        // Realmをインスタンス化してデータベースを取得!viewDidLoadでも行ったやつ
        let realm = try! Realm()

        //Realmインスタンスからaddを叩くと、データベースにレコードが追加される
        // textFieldの値をデータベースに追加する
        // write は refresh() が呼び出されたかのように Realm インスタンスを最新の Realm バージョンに更新し、該当する場合は通知を生成します。
        try! realm.write {
            realm.add(instanceTodoModel)
        }
        self.tableView.reloadData()
    }
}

extension ViewController: UITableViewDataSource {

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

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell1", for: indexPath)

        let item: TodoModel = self.itemList[indexPath.row]

        cell.textLabel?.text = item.koumoku

        return cell
    }

    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
        let realm = try! Realm()

        if editingStyle == .delete {
            // 削除したいデータを検索する。今回はdeleteしたいcellのindexpathの項目を削除したいので、それをobjectで指定。
            let deleteItem = realm.objects(TodoModel.self)[indexPath.row]

            do{
                // write は refresh() が呼び出されたかのように Realm インスタンスを最新の Realm バージョンに更新し、該当する場合は通知を生成します。
                try realm.write{
                    realm.delete(deleteItem)
                }
            }catch{
                    print("Error")
                }
            }
        tableView.reloadData()

        }
}
TodoModel.swift
import Foundation
import RealmSwift

class TodoModel: Object {
    @objc dynamic var koumoku: String? = nil
}

起動してみた

ツイートしてあるので、リンク貼っておきます。
https://twitter.com/vex3ex5frd2xcvg/status/1350637210106699777?s=21

参考サイト

https://qiita.com/pe-ta/items/616e0dbd364179ca284b
https://naoya-ono.com/swift/realm-update-delete/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

iosアプリ開発に便利なライブラリ一覧

概要

iosアプリ開発において、簡単に便利なライブラリを紹介します。
ライブラリのインストールはcocoa podsを利用しています。

目次

1.Alamofire
2.AlamofireImage
3.APIkit 
4.Reachability.swift
5.ObjectMapper
6.Cadable
7.Rswift
8.lottie-ios
9.PKHUD
10.GradientCircularProgress
11.Realm Swift
12.RxSwift
13.promiseKit
14.Bright-future
15.swiftStoreKit
16.Graphs
17.SwiftDate

ネットワーク系

Alamofire

アプリからネットワーク通信をしたい場合、定番なツール
swift標準機能のURLRequestを使用するより、シンプルで書きやすい

AlamofireImage

URLを指定して、ネットワーク上の画像を取得できる

APIkit

シンプルなコードが書ける

ネットワーク接続監視系

Reachability.swift

クロージャやローカル通知で接続状況の変化を受け取ることができる

デコーダ系

ObjectMapper

デコーダとして定番

Cadable

swift標準のデコーダ

リソースの定義系

Rswift

ソースコードの文字列を始めとするリソースの定義を構造体を使って自動的にリストアップしてくれる

アニメーション系

lottie-ios

リッチなアニメーションを作ることができる

インジケーター系

ソースコードの文字列を始めとするリソースの定義をstructを使って自動的にリストアップしてくれる

PKHUD

HUDを表示できる

GradientCircularProgress

データベース系

Realm Swift

データベースのコードをかんたんに書ける
アプリ自身にデータベースを持ち、サーバー側のデータベースと動機できるため、オフライン状態でもアプリを動作できる。
リレーションも使用可

非同期処理系

RxSwift

非同期処理のイベントを受け取ることができる

promiseKit

シンプルに非同期処理を実現できる

Bright-future

シンプルに非同期処理が書けるが、日本語記事が少ない

課金系

swiftStoreKit

簡単に課金処理が作れる

グラフ系

Graphs

簡単アプリでグラフを作成できる

日付系

SwiftDate

簡単に日付処理ができる

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

プログラミングで数学検定1級は合格できるのか

はじめに

この記事で取り扱っているのは、1~5問目です。(全7問中)

数検1級の難易度は

大学程度・一般レベル。日本数学検定協会によると、合格率は5.7%で、すべて記述式だそう。東大の入試問題よりしばしば難しいとも言われます。

どの問題を解くのか

数学検定1級1次試験 サンプル問題 のうち何問かを解いていこうと思います。(模範解答はここから入手できます。

実行環境

Python......paiza.io
FORTRAN......AtCoder コードテストの中のABC187のコードテスト

実際に解いていきましょう

1問目

問題1
2018n ≡ 2 mod(1000) を満たす正の整数nの最小値を求めよ。

となる。まず、modとはどういうものだろうか。

modとは
p ≡ q(mod n)のとき、p-qがnで割り切れる。

なんとなくわかりましたか?
では、例をみてみましょう。


3 ≡ 8(mod 5)
3-8は5で割り切れます。

こんな感じの記号です。

これを全探索(全てのパターンを試すアルゴリズム)で解いていこうと思います。(本当は1桁目で分類>2桁目で分類みたいな感じでとくのだろう)

Python

プログラム
n = 1
while True:
    if (2018*n-2)%1000 == 0:
        break
    n += 1

print(n)
出力
389

FORTRAN

プログラム
program question1
  do n = 1,1000
    !ここでは、mod 1000 なので、nが1001以上の値を取らないことが証明できます。
    if (mod((2018*n-2),1000) == 0) then
      print '(i0)', n
    end if
  end do
end
出力
389
889

よって、最も小さい389が答えだと考えられます(最初から1000と2018が偶数であるから500まで全探索でも良いのですが。)。

Swift

プログラム
var n = 0
while n < 1001{
    if (2018*n-2)%1000 == 0{
        print(n)
        break
    }
    n += 1
}

while文での実装です。

出力
389

解答を見たら正解でした。

2問目

tan(2 Arctan (1/3)+Arctan(1/12))を求めなさい。ただし、Arctan xはtan xの逆関数を表し、-π/2 < Arctan x < π/2 とします。

「Arctanはtanの逆関数」とは?

この記事に詳しく載っています。

これは普通に計算して、近い値を見つけていきたいと思います。

Python(精度 低)

プログラム
import math
inside = 2*math.degrees(math.atan(1/3))#tanの中身
inside += math.degrees(math.atan(1/12))
print(math.tan(math.radians(inside)))
出力
0.8888888888888887

だいたい、8/9くらいでしょうか(正解でした)。
本当はArctanの加法定理を使うのかな......

Python(精度 UP)

<方針>
- Arctanの加法定理を実現しよう
- 小数は誤差が出やすいので、分数で考えよう
- 上の二つの条件を満たす関数を作ろう。

Wikipediaにはこうある。

\arctan u+\arctan v=\arctan \left({\frac  {u+v}{1-uv}}\right){\pmod  \pi },\qquad uv\neq 1\,.

ここでは、-π/2~π/2でのみ定義しているため、(mod π)をなくして考える。u=a/b,v=c/dとして考える。問題ではその後、tanでまた元に戻しているため、(u+v)/(1-uv)のみ考えれば良い(tan(arctan(x)) = x)。結局、答えは(u+v)/(1-uv)なので、これを出力するプログラムを考える。

とりあえず、こんな関数を作ってみました。

from fractions import Fraction
def arctan_sum(a,b,c,d):
    u = Fraction(a,b)
    v = Fraction(c,d)
    return ((u+v),(1-u*v))

戻り値はタプルです。下のように書くと、

プログラム
from fractions import Fraction
def arctan_sum(a,b,c,d):
    u = Fraction(a,b)
    v = Fraction(c,d)
    return ((u+v),(1-u*v))
left = arctan_sum(1,3,1,3)
total = arctan_sum(left[0],left[1],1,12)
出力結果
8/9

綺麗に答えが出ました。

3問目

xyz空間内の4点(1,-4,1),(2,2,2),(2,-6,-3),(3,-2,-1)を頂点に持つ四面体の体積を求めよ。

サラスの公式を使って解きます。まず、(0,0,0)(x1,y1,z1),(x2,y2,z2),(x3,y3,z3)を頂点に持つ四面体の体積を求める関数を作る。しかし、これは(0,0,0)を頂点に持つ四面体を考えなければならないので、x1~z3を手計算(一番早そうなので)で求めていきたいの思います。

Python

関数
from fractions import Fraction
def sarasu(x1,y1,z1,x2,y2,z2,x3,y3,z3):
    return Fraction(abs(y1*z2*x3+z1*x2*y3+x1*y2*z3-z1*y2*x3-x1*z2*y3-y1*x2*z3),6)
プログラム全体
from fractions import Fraction
def sarasu(x1,y1,z1,x2,y2,z2,x3,y3,z3):
    return Fraction(abs(y1*z2*x3+z1*x2*y3+x1*y2*z3-z1*y2*x3-x1*z2*y3-y1*x2*z3),6)

print(sarasu(1,6,1,1,-2,-4,2,2,-2))
出力結果
3

これもあっさり答えが出ました。(正解でした。)

4問目(1)

  3次正方行列 A = \left(
    \begin{array}{ccc}
      4 & 1 & 1 \\
      1 & 2 & 1 \\
      1 & 1 & 2
    \end{array}
  \right) について次の問いに答えなさい。

①固有値を求めなさい。

Python

Pythonで固有値を求めることができるので、求めていこうと思います。

プログラム
import numpy as np
import numpy.linalg as LA

a = np.array([[4,1,1],[1,2,1],[1,1,2]])#固有値を求めたい行列


aeig_val = LA.eig(a)[0]
aeig_val = np.sort(aeig_val)

print(aeig_val)
出力結果
[1. 2. 5.]

リストにしようとすると、誤差が出るため、このような結果にしました。(答えは1,2,5なので、あってます。)

4問目(1)進化版

replaceで解答の形に変えました。

Python

プログラム(進化版)
import numpy as np
import numpy.linalg as LA

a = np.array([[4,1,1],[1,2,1],[1,1,2]])#固有値を求めたい行列


aeig_val = LA.eig(a)[0]
aeig_val = np.sort(aeig_val)

ans = str(aeig_val)
ans = ans.replace("[","").replace(".]","").replace(". ",", ")

print(ans)
出力結果
1, 2, 5

4問目(2)

固有値問題を数値的に解く - 高知大学、行列の累乗3 単位行列、行列の転置(行列) などを参考にして、求めていきたいと思います。これはやるだけで、大丈夫です。

Python

プログラム
import numpy as np
import numpy.linalg as LA

A = np.array([[4,1,1],[1,2,1],[1,1,2]])
I = np.array([[1,0,0],[0,1,0],[0,0,1]])

A3 = np.linalg.matrix_power(A, 3)#A^3
A2 = np.linalg.matrix_power(A, 2)#A^2

ans = A3-8*A2+18*A-12*I#そのまま演算子で計算
print(ans)
出力結果
[[2 1 1]
 [1 0 1]
 [1 1 0]]

わかりやすく書くと、

\left(
    \begin{array}{ccc}
      2 & 1 & 1 \\
      1 & 0 & 1 \\
      1 & 1 & 0
    \end{array}
  \right)

(これもまた正解でした)

5問目(1)

一定の期間内における機械の故障回数はポアソン分布に従うことが知られています。ある会社では2つの機械A, Bを使用しており、1年間で故障する回数が機械Aが平均2.5回、機械Bは平均4.5回のポアソン分布に従うとき、次の問いに答えなさい。ただし、A,Bが1年間に故障する回数は互いに独立であるとし、解答の際は1-6-6にあるポアソン分布表を用い、答えは小数第4位を四捨五入して小数第3位まで求めなさい。

①機械Aが1年間に4回以上故障する確率を求めなさい。

ポアソン分布というのは......

「ポアソン分布を表す確率関数は,

P(k) = (e^{-k}*λ^k) / k!

です。
つまり,単位時間あたり平均 λ 回起こるようなランダムなイベントが,単位時間に k 回発生する確率が P(k) です。」

高校数学の美しい物語 ポアソン分布の意味と平均・分散 より抜粋)

この問題では、壊れた回数が4回未満になる確率を全体から引く。このとき、λが2.5、kが0~3だとわかる。

Python

プログラム
zero_three = 0.0821+0.2052+0.2565+0.2138#足しただけ

print(round((1-zero_three)*1000)/1000)
出力結果
0.242

正解でした。

5問目(2)

一定の期間内における機械の故障回数はポアソン分布に従うことが知られています。ある会社では2つの機械A, Bを使用しており、1年間で故障する回数が機械Aが平均2.5回、機械Bは平均4.5回のポアソン分布に従うとき、次の問いに答えなさい。ただし、A,Bが1年間に故障する回数は互いに独立であるとし、解答の際は1-6-6にあるポアソン分布表を用い、答えは小数第4位を四捨五入して小数第3位まで求めなさい。

②機械A,Bが合わせて8回以上故障する確率を求めなさい。

まず、平均2.5回、4.5回のポアソン分布の値をリストにします。次に、故障した回数が8未満になる確率を求め、全体から引きます。

Python

プログラム
A = [0.0821,0.2052,0.2565,0.2138,0.1336,0.0668,0.0278,0.0099,0.0031,0.0009,0.0002]#平均2.5回のポアソン分布
B = [0.0111,0.0500,0.1125,0.1687,0.1898,0.1708,0.1281,0.0824,0.0463,0.0232,0.0104]#平均4.5回のポアソン分布

ans = 0
for i in range(8):
    for j in range(i+1):
        ans += A[i-j]*B[j]

print(round((1-ans)*1000)/1000)
出力結果
0.401

正解でした。

結論

合格します(合格ラインは5問)!ただ、普通に計算した方がプログラムを組むよりも早い問題もあります。

参考文献

注意

  • この記事は数学検定でのカンニングを推奨するものではありません。悪用しないでください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む