20200710のSwiftに関する記事は11件です。

Swiftのextensionをとは? 初心者が簡単にまとめてみました

はじめに

swiftの勉強を始めてみると、今まで使ったことのないコードや機能に出会うことが多いです。今回はその中の1つextensionの紹介をします。
修正点などありましたら、指摘していただくと嬉しいです。

extensionとは

extension 「拡張」という言葉の通り、クラス(class)や構造体(struct)
プロトコル(protocol)などに、関数(メソッド)や変数(プロパティ)を追加することができる機能です。

それなら普通にクラスや構造体にコードを追加すればいいじゃないかと思いますが(自分も思いましたが)、それ以上の機能や便利な面もあるので、使いこなしていきましょう。

まずは基本的なことから行きます。

具体的な書き方

extension 拡張する型の名前 {
  //追加するメソッドやプロパティを記述する
}

書き方は簡単です。
拡張したいクラスや構造体の名前と、追加のメソッドやプロパティを記述します。
自分で定義したクラスなどを入れて、新しいメソッドを追加することが簡単にできます。

extensionの記述例

最初に言ったように、自分で作ったクラスや構造体ならその部分にコードを直接記述すれば、メッソドとプロパティは追加できます。しかし、自分で定義していないもの(元々存在しているもの)に関してはその操作ができません。

そこでextensionの1つ目の素晴らしい点が、自分が作ったものでなくてもSwiftに元々あるクラスなどにも機能を拡張することができるという点です。例えばとても身近なIntやStringといったクラスに新たなメソッドを定義することができます。

extension Int {
    func niceNumber() {
        print("Wow! Nice number!")
    }
}

このようなおかしなメソッドも追加することができ、実際に使うことができます。

let number = 5
number.niceNumber() //=> Wow! Nice Number!

これはextensionを使わないとできないことだと思います。

ちなみにIntStringはオープンソースになっていて、GitHub上で誰でも中身を見ることができます。またUITextFieldなどはオープンソースではないですが、もちろん拡張することはできます。

プロトコルの拡張

素晴らしい点2つ目は、プロトコルの拡張です。
プロコトルというのは、メソッドやプロパティの中身を定義することができませんでした。そのため、それぞれのプロトコルを適用したクラスなどで中身を書いていく必要がありました。

//プロトコルの定義
protocol Canfly {
    func fly()
}

//プロトコルを適用しているクラス
class Eagle: Canfly {
    func fly() {
        print("The eagle can fly")//1つ1つメソッドの処理を書く
    }
}

//プロトコルを適用しているクラス
class Airplane: Canfly {
    func fly() {
        print("The plane can fly")//1つ1つメソッドの処理を書く
    }
}

ところがextensionを使うことで、その中身を事前に定義することができるのです。
書き方は今までと一緒です。

上記の例をそのまま使うと

extension Canfly {
    func fly() {
        print("The object can fly")
    }
}

こうすることによって、Canflyプロトコルのflyメソッドの中身を定義することができました。

すると

class Eagle: Canfly {
    //fly()メソッドの定義をしなくても大丈夫
}

class Airplane: Canfly {
    //fly()メソッドの定義をしなくても大丈夫
}

let myEagle = Eagle()
let myPlane = Airplane()

myEagle.fly() //=> The object can fly
myPlane.fly() //=> The object can fly

このようにして、コードの量や負担を減らすことができました。

今まで既存のプロトコルを適用する際に、全部のメッソドを呼び出したり定義していないのに大丈夫なのかなと思っていた方も多いと思いますが、それらは全てextensionをつかってappleさんが事前に定義してくれているから大丈夫なんです。

コードを見やすくする

extension最後の活用方法は、extensionを使うことでコードがすっきりして見やすくなります。

具体的には以下のように、1つのクラスにたくさんのプロトコルを適用している場合、どのメソッドがどのプロトコルに対応している操作なのか、コードが膨大になり分わかりにくくなります。

import UIKit
// プロトコルを2つも適用している、、、
class WeatherViewController: UIViewController, UITextFieldDelegate, UINavigationControllerDelegate {

    @IBOutlet weak var conditionImageView: UIImageView!
    @IBOutlet weak var temperatureLabel: UILabel!
    @IBOutlet weak var cityLabel: UILabel!
    @IBOutlet weak var searchTextField: UITextField!

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

    }

    //どのメソッドが
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        .....
    }
    //どのプロパティに対応しているのか    
    func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
        ......
    }
    //多すぎてわからなくなる
    func textFieldDidEndEditing(_ textField: UITextField) {
        .......
    }
    //なんの操作をしているだろう    
    func navigationController() {
        ........
    }
}

そこでextensionを使うことで、プロトコルごとにコードを記述する場所を分けるのです。

具体的には以下のようにすることができます。

import UIKit
class WeatherViewController: UIViewController, UITextFieldDelegate, UINavigationControllerDelegate {

    @IBOutlet weak var conditionImageView: UIImageView!
    @IBOutlet weak var temperatureLabel: UILabel!
    @IBOutlet weak var cityLabel: UILabel!
    @IBOutlet weak var searchTextField: UITextField!

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

    }
}

//プロトコルごとに分ける----------------------------------------------------------------------------------
extension WeatherViewController: UITextFieldDelegate {

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        .....
    }

    func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
        ......
    }

    func textFieldDidEndEditing(_ textField: UITextField) {
        .......
    }
}

//プロトコルごとに分ける----------------------------------------------------------------------------------
extension WeatherViewController: UINavigationControllerDelegate {

    func navigationController(........) {
        ........
    }
}

これでプロトコルとメソッドの対応関係もしっかり分かり、コードもすっきりしました。

以上でextensionの使い方等の解説を終わります。これはプログラミング初心者が簡単にまとめたものなので、修正などがありましたらご指摘お願いします。

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

Swiftのextensionをわかりやすく解説

extensionとは

extension 「拡張」という言葉の通り、クラス(class)や構造体(struct)
プロトコル(protocol)などに、関数(メソッド)や変数(プロパティ)を追加することができる機能です。

それなら普通にクラスや構造体にコードを追加すればいいじゃないかと思いますが(自分も思いましたが)、それ以上の機能や便利な面もあるので、使いこなしていきましょう。

まずは基本的なことから行きます。

具体的な書き方

extension 拡張する型の名前 {
  //追加するメソッドやプロパティを記述する
}

書き方は簡単です。
拡張したいクラスや構造体の名前と、追加のメソッドやプロパティを記述します。
自分で定義したクラスなどを入れて、新しいメソッドを追加することが簡単にできます。

extensionの記述例

最初に言ったように、自分で作ったクラスや構造体ならその部分にコードを直接記述すれば、メッソドとプロパティは追加できます。しかし、自分で定義していないもの(元々存在しているもの)に関してはその操作ができません。

そこでextensionの1つ目の素晴らしい点が、自分が作ったものでなくてもSwiftに元々あるクラスなどにも機能を拡張することができるという点です。例えばとても身近なIntやStringといったクラスに新たなメソッドを定義することができます。

extension Int {
    func niceNumber() {
        print("Wow! Nice number!")
    }
}

このようなおかしなメソッドも追加することができ、実際に使うことができます。

let number = 5
number.niceNumber() //=> Wow! Nice Number!

これはextensionを使わないとできないことだと思います。

ちなみにIntStringはオープンソースになっていて、GitHub上で誰でも中身を見ることができます。またUITextFieldなどはオープンソースではないですが、もちろん拡張することはできます。

プロトコルの拡張

素晴らしい点2つ目は、プロトコルの拡張です。
プロコトルというのは、メソッドやプロパティの中身を定義することができませんでした。そのため、それぞれのプロトコルを適用したクラスなどで中身を書いていく必要がありました。

//プロトコルの定義
protocol Canfly {
    func fly()
}

//プロトコルを適用しているクラス
class Eagle: Canfly {
    func fly() {
        print("The eagle can fly")//1つ1つメソッドの処理を書く
    }
}

//プロトコルを適用しているクラス
class Airplane: Canfly {
    func fly() {
        print("The plane can fly")//1つ1つメソッドの処理を書く
    }
}

ところがextensionを使うことで、その中身を事前に定義することができるのです。
書き方は今までと一緒です。

上記の例をそのまま使うと

extension Canfly {
    func fly() {
        print("The object can fly")
    }
}

こうすることによって、Canflyプロトコルのflyメソッドの中身を定義することができました。

すると

class Eagle: Canfly {
    //fly()メソッドの定義をしなくても大丈夫
}

class Airplane: Canfly {
    //fly()メソッドの定義をしなくても大丈夫
}

let myEagle = Eagle()
let myPlane = Airplane()

myEagle.fly() //=> The object can fly
myPlane.fly() //=> The object can fly

このようにして、コードの量や負担を減らすことができました。

今まで既存のプロトコルを適用する際に、全部のメッソドを呼び出したり定義していないのに大丈夫なのかなと思っていた方も多いと思いますが、それらは全てextensionをつかってappleさんが事前に定義してくれているから大丈夫なんです。

コードを見やすくする

extension最後の活用方法は、extensionを使うことでコードがすっきりして見やすくなります。

具体的には以下のように、1つのクラスにたくさんのプロトコルを適用している場合、どのメソッドがどのプロトコルに対応している操作なのか、コードが膨大になり分わかりにくくなります。

import UIKit
// プロトコルを2つも適用している、、、
class WeatherViewController: UIViewController, UITextFieldDelegate, UINavigationControllerDelegate {

    @IBOutlet weak var conditionImageView: UIImageView!
    @IBOutlet weak var temperatureLabel: UILabel!
    @IBOutlet weak var cityLabel: UILabel!
    @IBOutlet weak var searchTextField: UITextField!

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

    }

    //どのメソッドが
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        .....
    }
    //どのプロパティに対応しているのか    
    func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
        ......
    }
    //多すぎてわからなくなる
    func textFieldDidEndEditing(_ textField: UITextField) {
        .......
    }
    //なんの操作をしているだろう    
    func navigationController() {
        ........
    }
}

そこでextensionを使うことで、プロトコルごとにコードを記述する場所を分けるのです。

具体的には以下のようにすることができます。

import UIKit
class WeatherViewController: UIViewController, UITextFieldDelegate, UINavigationControllerDelegate {

    @IBOutlet weak var conditionImageView: UIImageView!
    @IBOutlet weak var temperatureLabel: UILabel!
    @IBOutlet weak var cityLabel: UILabel!
    @IBOutlet weak var searchTextField: UITextField!

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

    }
}

//プロトコルごとに分ける----------------------------------------------------------------------------------
extension WeatherViewController: UITextFieldDelegate {

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        .....
    }

    func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
        ......
    }

    func textFieldDidEndEditing(_ textField: UITextField) {
        .......
    }
}

//プロトコルごとに分ける----------------------------------------------------------------------------------
extension WeatherViewController: UINavigationControllerDelegate {

    func navigationController(........) {
        ........
    }
}

これでプロトコルとメソッドの対応関係もしっかり分かり、コードもすっきりしました。

以上でextensionの使い方等の解説を終わります。これはプログラミング初心者が簡単にまとめたものなので、修正などがありましたらご指摘お願いします。

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

Swiftのextensionを簡単にまとめました

extensionとは

extension 「拡張」という言葉の通り、クラス(class)や構造体(struct)
プロトコル(protocol)などに、関数(メソッド)や変数(プロパティ)を追加することができる機能です。

それなら普通にクラスや構造体にコードを追加すればいいじゃないかと思いますが(自分も思いましたが)、それ以上の機能や便利な面もあるので、使いこなしていきましょう。

まずは基本的なことから行きます。

具体的な書き方

extension 拡張する型の名前 {
  //追加するメソッドやプロパティを記述する
}

書き方は簡単です。
拡張したいクラスや構造体の名前と、追加のメソッドやプロパティを記述します。
自分で定義したクラスなどを入れて、新しいメソッドを追加することが簡単にできます。

extensionの記述例

最初に言ったように、自分で作ったクラスや構造体ならその部分にコードを直接記述すれば、メッソドとプロパティは追加できます。しかし、自分で定義していないもの(元々存在しているもの)に関してはその操作ができません。

そこでextensionの1つ目の素晴らしい点が、自分が作ったものでなくてもSwiftに元々あるクラスなどにも機能を拡張することができるという点です。例えばとても身近なIntやStringといったクラスに新たなメソッドを定義することができます。

extension Int {
    func niceNumber() {
        print("Wow! Nice number!")
    }
}

このようなおかしなメソッドも追加することができ、実際に使うことができます。

let number = 5
number.niceNumber() //=> Wow! Nice Number!

これはextensionを使わないとできないことだと思います。

ちなみにIntStringはオープンソースになっていて、GitHub上で誰でも中身を見ることができます。またUITextFieldなどはオープンソースではないですが、もちろん拡張することはできます。

プロトコルの拡張

素晴らしい点2つ目は、プロトコルの拡張です。
プロコトルというのは、メソッドやプロパティの中身を定義することができませんでした。そのため、それぞれのプロトコルを適用したクラスなどで中身を書いていく必要がありました。

//プロトコルの定義
protocol Canfly {
    func fly()
}

//プロトコルを適用しているクラス
class Eagle: Canfly {
    func fly() {
        print("The eagle can fly")//1つ1つメソッドの処理を書く
    }
}

//プロトコルを適用しているクラス
class Airplane: Canfly {
    func fly() {
        print("The plane can fly")//1つ1つメソッドの処理を書く
    }
}

ところがextensionを使うことで、その中身を事前に定義することができるのです。
書き方は今までと一緒です。

上記の例をそのまま使うと

extension Canfly {
    func fly() {
        print("The object can fly")
    }
}

こうすることによって、Canflyプロトコルのflyメソッドの中身を定義することができました。

すると

class Eagle: Canfly {
    //fly()メソッドの定義をしなくても大丈夫
}

class Airplane: Canfly {
    //fly()メソッドの定義をしなくても大丈夫
}

let myEagle = Eagle()
let myPlane = Airplane()

myEagle.fly() //=> The object can fly
myPlane.fly() //=> The object can fly

このようにして、コードの量や負担を減らすことができました。

今まで既存のプロトコルを適用する際に、全部のメッソドを呼び出したり定義していないのに大丈夫なのかなと思っていた方も多いと思いますが、それらは全てextensionをつかってappleさんが事前に定義してくれているから大丈夫なんです。

コードを見やすくする

extension最後の活用方法は、extensionを使うことでコードがすっきりして見やすくなります。

具体的には以下のように、1つのクラスにたくさんのプロトコルを適用している場合、どのメソッドがどのプロトコルに対応している操作なのか、コードが膨大になり分わかりにくくなります。

import UIKit
// プロトコルを2つも適用している、、、
class WeatherViewController: UIViewController, UITextFieldDelegate, UINavigationControllerDelegate {

    @IBOutlet weak var conditionImageView: UIImageView!
    @IBOutlet weak var temperatureLabel: UILabel!
    @IBOutlet weak var cityLabel: UILabel!
    @IBOutlet weak var searchTextField: UITextField!

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

    }

    //どのメソッドが
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        .....
    }
    //どのプロパティに対応しているのか    
    func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
        ......
    }
    //多すぎてわからなくなる
    func textFieldDidEndEditing(_ textField: UITextField) {
        .......
    }
    //なんの操作をしているだろう    
    func navigationController() {
        ........
    }
}

そこでextensionを使うことで、プロトコルごとにコードを記述する場所を分けるのです。

具体的には以下のようにすることができます。

import UIKit
class WeatherViewController: UIViewController, UITextFieldDelegate, UINavigationControllerDelegate {

    @IBOutlet weak var conditionImageView: UIImageView!
    @IBOutlet weak var temperatureLabel: UILabel!
    @IBOutlet weak var cityLabel: UILabel!
    @IBOutlet weak var searchTextField: UITextField!

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

    }
}

//プロトコルごとに分ける----------------------------------------------------------------------------------
extension WeatherViewController: UITextFieldDelegate {

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        .....
    }

    func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
        ......
    }

    func textFieldDidEndEditing(_ textField: UITextField) {
        .......
    }
}

//プロトコルごとに分ける----------------------------------------------------------------------------------
extension WeatherViewController: UINavigationControllerDelegate {

    func navigationController(........) {
        ........
    }
}

これでプロトコルとメソッドの対応関係もしっかり分かり、コードもすっきりしました。

以上でextensionの使い方等の解説を終わります。これはプログラミング初心者が簡単にまとめたものなので、修正などがありましたらご指摘お願いします。

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

xibファイルを読み込んでNSTableViewを作成する

概要

  • 以下のような簡単なテーブルを作っていきます。
  • (基本的な所は省略して、忘備録的に書いていますので細かい所はサンプル参照ということでご容赦を…。)

-w450

  • また以下のテーブルのセルはxibファイルから読み込んだものを使用しています。

-w450

GitHub

参考

テキストだけの単純なテーブル

Storyboard側

  • TableViewdelegatedatasourceをコントローラにバインディング

-w1682

  • CellViewIdentifierMyViewに設定しておく

-w1703

コード

  • 表示するデータを用意
var messages = ["sample message 1",
                "sample message 2",
                "sample message 3"]
  • テーブル表示に必要なメソッド2種を実装する
  • NSUserInterfaceItemIdentifier(rawValue: "MyView")により、
    Storyboardで指定したMyViewを読み込んでコード内で使用することができる
extension StandardTableViewController : NSTableViewDelegate, NSTableViewDataSource {
    func numberOfRows(in tableView: NSTableView) -> Int {
        return messages.count
    }

    func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
        guard let cellView = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "MyView"), owner: self) as? NSTableCellView else {
            return NSTableCellView()
        }

        cellView.textField?.stringValue = messages[row]

        return cellView
    }
}

カスタムXibを用いたテーブルビュー

概要

  • 別のXibファイルをセルに使用したい場合の実装です。

実装

カスタムセルのクラス(CustomTableCellView.swift)

  • カスタムセルのため、NSTableCellViewのサブクラスを作成します。
  • テーブルのdelegate設定等は前述と同じなので割愛しています。
protocol CustomTableCellViewDelegate: class {
    func selectionButtonClicked(for cell: NSTableCellView)
}

class CustomTableCellView: NSTableCellView {

    @IBOutlet weak var cellImageView: NSImageView!
    @IBOutlet weak var titleLabel: NSTextField!
    @IBOutlet weak var descriptionLabel: NSTextField!
    @IBOutlet weak var selectionButton: NSButton!

    var delegate: CustomTableCellViewDelegate?

    override func draw(_ dirtyRect: NSRect) {
        super.draw(dirtyRect)

    }

    func configure(for cellData: CustomCellData) {
        self.cellImageView.image          = cellData.image
        self.titleLabel.stringValue       = cellData.title
        self.descriptionLabel.stringValue = cellData.descriptionText
    }


    // MARK: - Actions

    @IBAction func selectionButtonClicked(_ sender: NSButton) {
        // セルのボタンのアクションをコントローラに返すため、delegateを使用する
        delegate?.selectionButtonClicked(for: self)
    }

}

カスタムセルのxib(CustomTableCellView.xib)

  • カスタムセルのUI側です。
  • クラスを作成するCustomTableCellViewに指定します
  • セルのidentifier等の設定は不要です。
    • CustomTableViewControllertableView.registerで設定するからですね

-w1412

定数定義ファイル(Konst.swift)

  • identifier等に使用する定数をファイルで定義しておきます
struct Konst {

    struct SegueIdentifier {
        static let showStandardTableViewController = "ShowStandardTableViewController"
        static let showCustomTableViewController   = "ShowCustomTableViewController"
    }

    struct CellIdentifier {
        static let customTableCellView = "CustomTableCellView"
    }

    struct NibName {
        static let customTableCellView = "CustomTableCellView"
    }
}

ビューコントローラ(CustomTableViewController.swift)

  • 別のxibファイルから読み込むため、viewDidLoadtableViewxibの登録を行う
    • iOSでカスタムセルを使う際と同じですね。
// 別のXibファイルから読み込む場合は登録が必要
tableView.register(NSNib(nibNamed: Konst.NibName.customTableCellView, bundle: nil),
                    forIdentifier: NSUserInterfaceItemIdentifier(rawValue: Konst.CellIdentifier.customTableCellView))
tableView.reloadData()
  • 同様にテーブル表示に必要なプロトコルメソッドを実装
  • cellのUI設定はcell側 = Model側に任せてしまう。教本でよく見る実装です。
    • cellView.configure(for: cellDataList[row])
// MARK: - NSTableViewDelegate, NSTableViewDataSource Methods

extension CustomTableViewController: NSTableViewDelegate, NSTableViewDataSource {
    func numberOfRows(in tableView: NSTableView) -> Int {
        return cellDataList.count
    }

    func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
        guard let cellView = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: Konst.CellIdentifier.customTableCellView), owner: self)
            as? CustomTableCellView else {
            return NSTableCellView()
        }

        cellView.delegate = self
        cellView.configure(for: cellDataList[row])

        return cellView
    }
}
  • カスタムセル内のボタンのアクションを受け取るため、delegateパターンを使用しています。
// CustomTableCellViewDelegate Methods

extension CustomTableViewController: CustomTableCellViewDelegate {
    func selectionButtonClicked(for cell: NSTableCellView) {
        let rowIndex = tableView.row(for: cell)  // 選択されたcellViewのIndexを取得できる
        print("selected row: [\(rowIndex)]")
    }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Swiftで大文字か小文字か判定する

CharacterのisUppercaseプロパティは大文字かどうかを、isLowercaseは小文字かどうかを判定してくれます。

let a:Character = "a"//Character(readLine()!)
if a.isUppercase {
    print("小文字です")
} else {
    print("大文字です")
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Swiftで大文字か小文字か判定する&アルファベットが格納された配列

CharacterのisUppercaseプロパティは大文字かどうかを、isLowercaseは小文字かどうかを判定してくれます。

let a:Character = "a"//Character(readLine()!)
if a.isUppercase {
    print("小文字です")
} else {
    print("大文字です")
}

["a","b","c"..."z"]["A","B","C"..."Z"]は使えそう
参考

let upChaAry = (65...90).map{ String(Character(UnicodeScalar($0)!)) }
let lowChaArr = (97...122).map{String(Character(UnicodeScalar($0)!))}
print(lowChaArr)
print(upChaAry)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

今日の気になる&調べた

Sasfariのタブを残しておいたりする代わりにここに記載・追記していこうと思う。

気になる

調べた

LINE

SwiftUI

SF Symbols

C# on Mac

GUID とか OTPとか

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

AIZU ONLINE JUDGE の問題をSwiftでやってみた(プログラミング入門 配列編)

トピック #1 配列

AIZU ONLINE JUDGEの問題にSwiftで解答したものになります。競技プログラミングは普段やりませんので、こうしたほうが簡単!などがあればコメントで教えて下さい。
ブラウザでプログラミング・実行ができる「オンライン実行環境」paiza.IOでテスト出力が行えます

6_A

問題
与えられた数列を逆順に出力するプログラムを作成して下さい。入力は以下の形式で与えられます
n
a_1 a_2 a_3...a_n
逆順の数列を1行に出力して下さい。数列の要素の間に1つの空白を入れて下さい(最後の数の後に空白は入らないことに注意して下さい)。
解答

let a = Int(readLine()!)!
var arr = readLine()!.split(separator: " ").map({Int($0)})
print(arr.reversed())

6_

問題

解答

let a = Int(readLine()!)!
var sArr:[Int] = []
var hArr:[Int] = []
var cArr:[Int] = []
var dArr:[Int] = []

for i in 0 ..< a {
    var b = readLine()!.split(separator: " ")
    var num = Int(b[1]) ?? 0
    switch b[0] {
    case "S":
        sArr.append(num)
    case "H":
        hArr.append(num)
    case "C":
        cArr.append(num)
    case "D":
        dArr.append(num)
    default:
        break
    }
}

func checkTramp(_ tramp: [Int]) -> [Int] {
    var notHaveArr:[Int] = []
    for i in 0 ..< tramp.count {
        if tramp.contains(i) == false {
            notHaveArr.append(i)
        }
    }
    return notHaveArr
}

for i in checkTramp(sArr) {
    print("S \(i)")
}
for i in checkTramp(hArr) {
    print("H \(i)")
}
for i in checkTramp(cArr) {
    print("C \(i)")
}
for i in checkTramp(dArr) {
    print("D \(i)")
}

6_B

問題
太郎が花子と一緒にトランプ遊びをしようとしたところ、52枚あるはずのカードが n 枚のカードしか手元にありません。これらの n 枚のカードを入力として、足りないカードを出力するプログラムを作成して下さい。

太郎が最初に持っていたトランプはジョーカーを除く52枚のカードです。

52枚のカードは、スペード、ハート、クラブ、ダイヤの4つの絵柄に分かれており、各絵柄には13のランクがあります。
入力
最初の行に太郎が持っているカードの枚数 n (n ≤ 52)が与えられます。

続いて n 組のカードがそれぞれ1行に与えられます。各組は1つの空白で区切られた文字と整数です。文字はカードの絵柄を表し、スペードが'S'、ハートが'H'、クラブが'C'、ダイヤが'D'で表されています。整数はそのカードのランク(1 〜 13)を表しています。
出力
足りないカードをそれぞれ1行に出力して下さい。各カードは入力と同様に1つの空白で区切られた文字と整数です。
解答

let a = Int(readLine()!)!
var sArr:[Int] = []
var hArr:[Int] = []
var cArr:[Int] = []
var dArr:[Int] = []

for i in 1 ... a {
    var b = readLine()!.split(separator: " ")
    var num = Int(b[1]) ?? 0
    switch b[0] {
    case "S":
        sArr.append(num)
    case "H":
        hArr.append(num)
    case "C":
        cArr.append(num)
    case "D":
        dArr.append(num)
    default:
        break
    }
}

func checkTramp(_ tramp: [Int]) -> [Int] {
    var notHaveArr:[Int] = []
    for i in 1 ... tramp.count {
        if tramp.contains(i) == false {
            notHaveArr.append(i)
        }
    }
    return notHaveArr
}

for i in checkTramp(sArr) {
    print("S \(i)")
}
for i in checkTramp(hArr) {
    print("H \(i)")
}
for i in checkTramp(cArr) {
    print("C \(i)")
}
for i in checkTramp(dArr) {
    print("D \(i)")
}

6_C 公舎の入居数

問題
A大学は1フロア10部屋、3階建ての公舎4棟を管理しています。公舎の入居・退去の情報を読み込み、各部屋の入居者数を出力するプログラムを作成して下さい。

n件の情報が与えられます。各情報では、4つの整数b, f, r, vが与えられます。これは、b棟f階のr番目の部屋にv人が追加で入居したことを示します。vが負の値の場合、-v人退去したことを示します。

最初、全ての部屋には誰も入居していないものとします。
入力
最初の行に情報の数 n が与えられます。
続いて n 件の情報が与えられます。各情報には4つの整数 b, f, r, v が空白区切りで1行に与えられます。
出力
4棟について入居者数を出力して下さい。各棟について、1階、2階、3階の順に入居者数を出力します。各階については、1番目、2番目、・・・、10番目の部屋の入居者数を順番に出力します。入居者数の前には1つの空白を出力して下さい。また、各棟の間には####################(20個の#)で区切って下さい。
出力例

3
1 1 3 8
3 2 2 7
4 3 8 1
0 0 8 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0
####################
 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0
####################
 0 0 0 0 0 0 0 0 0 0
 0 7 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0
####################
 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 1 0 0

解答

let a = Int(readLine()!)!
var room1 = [[Int]](repeating: [Int](repeating: 0, count: 10), count: 3)
var room2 = [[Int]](repeating: [Int](repeating: 0, count: 10), count: 3)
var room3 = [[Int]](repeating: [Int](repeating: 0, count: 10), count: 3)
var room4 = [[Int]](repeating: [Int](repeating: 0, count: 10), count: 3)

func make(_ b: Int, _ f: Int, _  r: Int, _ v: Int) -> Void {
    switch b {
    case 1:
        room1[f-1][r-1] += v
    case 2:
        room2[f-1][r-1] += v
    case 3:
        room3[f-1][r-1] += v
    case 4:
        room4[f-1][r-1] += v
    default:
        break
    }
}

for i in 0 ..< a {
    var c = readLine()!.split(separator: " ").map({Int($0)!})
    make(c[0], c[1], c[2], c[3])
}


for i in 0 ..< 3 {
    for j in 0 ..< 10 {
    print(room1[i][j], terminator: " ")
    }
    print("\n")
}
print(String(repeating: "#", count: 20))
for i in 0 ..< 3 {
    for j in 0 ..< 10 {
    print(room2[i][j], terminator: " ")
    }
    print("\n")
}
print(String(repeating: "#", count: 20))
for i in 0 ..< 3 {
    for j in 0 ..< 10 {
    print(room3[i][j], terminator: " ")
    }
    print("\n")
}
print(String(repeating: "#", count: 20))
for i in 0 ..< 3 {
    for j in 0 ..< 10 {
    print(room4[i][j], terminator: " ")
    }
    print("\n")
}

6_D ベクトルと行列の積

問題
長いので省略
サイトを見て下さい。

解答

let a = readLine()!.split(separator: " ").map({Int($0)!})
var matrix = [[Int]]()
var vector = [Int]()
var solution = [Int](repeating: 0, count: a[0])

for i in 0 ..< a[0] {
    var m1 = readLine()!.split(separator: " ").map({Int($0)!})
    matrix.append(m1)
}

for i in 0 ..< a[1] {
    vector.append(Int(readLine()!)!)
}

for i in 0 ..< a[0] {
    for j in 0 ..< a[1] {
        solution[i] += matrix[i][j] * vector[j]
    }
}
for i in solution {
    print(i)
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AIZU ONLINE JUDGE の問題をSwiftでやってみた(プログラミング入門 構造化プログラムⅠ編)

トピック #1 構造化プログラムⅠ

AIZU ONLINE JUDGEの問題にSwiftで解答したものになります。競技プログラミングは普段やりませんので、こうしたほうが簡単!などがあればコメントで教えて下さい。

5_A 長方形の描画

問題
入力される二つの数字の組み合わせに対して以下のような長方形を出力して下さい。
####
####
####
(3,4)
入力は複数のデータセットから構成されています。
H W
H, W がともに 0 のとき、入力の終わりとします。

解答

let a = readLine()!.split(separator: " ").map({Int($0)!})
while a[0] != 0 && a[1] != 0 {
    for _ in 0 ..< a[0] {
        print(String(repeating: "#", count: a[1]))
    }
}
let a = readLine()!.split(separator: " ").map({Int($0)!})
while a[0] != 0 && a[1] != 0 {
    for _ in 0 ..< a[0] {
        for _ in 0 ..< a[1] {
            print("#")
        }
    }
}

が模範解答に近い形なのですが、出力に改行が含まれてしまうためString(repeating: , count: )を用いました。

5_B フレームの描画

問題
5_Aの続き
(3,4)に対して
####
#。。#
####
となるようにして下さい。
解答

let a = readLine()!.split(separator: " ").map({Int($0)!})
while a[0] != 0 && a[1] != 0 {
    for i in 0 ..< a[0] {
        if i == 0  || i == a[0] - 1{
            print(String(repeating: "#", count: a[1]))
        } else {
            var b = String(repeating: ".", count: a[1] - 2)
            print("#\(b)#")
        }
    }
}

5_C チェスボードの描画

問題
5_Bの続き
(3,4)に対して
#。#。
。#。#
#。#。
となるように出力してください。
解答

let a = readLine()!.split(separator: " ").map({Int($0)!})
while a[0] != 0 && a[1] != 0 {
    for i in 0 ..< a[0] {
        if i.isMultiple(of: 2) {
            if a[1].isMultiple(of: 2) {
            print(String(repeating: "#.", count: a[1]/2))
            } else {
                var b = String(repeating: "#.", count: a[1]/2 - 1)
                print("\(b).")
            }
        } else {
            if a[1].isMultiple(of: 2) {
            print(String(repeating: ".#", count: a[1]/2))
            } else {
                var b = String(repeating: ".#", count: a[1]/2 - 1)
                print("\(b)#")
            }
        }
    }
}

5_D 構造化プログラミング

問題
入力された数字nに対しnまでに含まれる3の倍数または3を含む数字を出力して下さい。(世界のナベアツ)
解答

let a = Int(readLine()!)!
var arr:[String] = []

for i in 1 ... a {
    arr.append(String(i))
}

func check(_ num: [String]) -> [Int] {
    var resultArr:[String] = []
    for i in num {
        if Int(i)!.isMultiple(of: 3){
            resultArr.append(i)
        }
    }
    print(resultArr)
    var arr = num.filter({Int($0)! % 3 != 0}).map({String($0)})
    print(arr)
    for i in arr {
        if i.contains("3") {
            resultArr.append(i)
        }
    }
    return resultArr.map({Int($0)!})

}
print(check(arr).sorted())
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Firestoreでユーザー別のいいね一覧を作る時

この度、初めてアプリをリリースさせて頂きました?
そして、制作中に一番苦労したCloud Firestoreの部分について書き残しておこうと思います✨

苦労した点としては、

スクリーンショット 2020-07-09 23.12.29.png

↑投稿されている画像に対してイイねをした場合、
写真のように、イイねした物の一覧を見る事ができるLike画面を作りました。

しかし、、、!

スクリーンショット 2020-07-09 23.13.07.png

Aの人がイイねした物が、Bの人がイイねを押していなくてもBの人のLike画面にも表示されていました。

今回は、
Aの人がイイねした物がAの人にしか見えないように、
Bの人がイイねした物がBの人にしか見えないように
 する解決策を見つけたので
書いていきます ↓ ↓ ↓

CloudFirestoreの構造

cloud1

このようにLikeIdにUser の ID (user.uid)を配列(Array型)で入れたらうまくいきました?

コード1(イイねする投稿が表示されている画面)

 func likeSwipe(){
       let saveDocument = Firestore.firestore()
        let user = Auth.auth().currentUser

        let docId = UserDefaults.standard.object(forKey: "docId") as! String

        let addDocument = saveDocument.collection("Posts")

        let query = addDocument.document(docId)

        query.updateData([
            "LikeId" : FieldValue.arrayUnion([user!.uid])
        ])

↑これをイイねボタンを押した時の動作に加えてください。 

これで、currentUserのUserIDがLikeIdに加えられます

コード2(Like画面_イイねした投稿の一覧を見る事ができる画面)

 func fetchData(completion: @escaping () -> Void){

      let user = Auth.auth().currentUser
      let saveDocument = Firestore.firestore()
      let uploadDocument = saveDocument.collection("Posts")


      let query = uploadDocument.whereField("LikeId",  arrayContains: user!.uid)

        query.getDocuments { (querySnapshot, error) in

↑これでquery(ユーザーが値をLikeIdに入れているかを検索)して
ユーザーがイイねしたもの(LikeIdに入れた物)のみが表示されるようになります
最後のコード以降は引っ張ってくるデーターを通常通りかけばオケです。

https://firebase.google.com/docs/firestore/query-data/get-data?hl=ja
(↑最後のコード以降の参考になれば、、)

おまけ(削除するときのコード)

Cellを消した時(投稿のイイねを外した時)

    let docId = self.documentIds[indexPath.row]

    let user = Auth.auth().currentUser
    let saveDocument = Firestore.firestore()
    let uploadDocument = saveDocument.collection("Posts")

    uploadDocument.document(docId).updateData([
                     "LikeId": FieldValue.arrayRemove([user!.uid])
                ])

このように、ArrayをRemoveすることで自分のイイね一覧から消えても、
他の人のイイね一覧には残ったまんまです。

以上

これで、Cloud Firestoreを使ったユーザー別のいいね一覧を作れると思います☺️

もし良ければ、ダウンロードしてみてください?✨
https://apps.apple.com/jp/app/baggle/id1518188746

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

コーチマーク+アニメーションでスワイプで削除する操作を表現する

はじめに

コーチマークとUIViewのアニメーションを組み合わせて、スワイプで削除する操作を表現してみました。

コーチマークについて

コーチマークとは・・・
 実際の画面の上にオーバーレイや吹き出しを出して
 画面上のボタンなどの使い方を案内してくれるやつです。

 アプリで初めて開く画面とかでときどきに見かけますね('・ω・`)

スワイプ削除

iOSのTableViewでは、セルをスワイプで削除する機能が簡単に実装できますし、
アプリユーザにとっても慣れている操作の一つではないかと思います(^ω^)

ただ、削除ボタンみたいに目に見えてわかる機能ではないので、
ユーザ全員が当たり前のようにスワイプで削除できると認識してくれるとは限りません。。。

そこで、初めて画面を開いた時にコーチマークを利用して、
スワイプで削除できるよっていうことを案内してみたいと思います!

実装

今回は、Instructionsを使用してコーチマークを実装しました!

Instructionsの実装方法は、こちらの記事を参考にさせていただきましたm(_ _)m
 → swift 簡単でおしゃれなチュートリアルライブラリ,Instructions

今回は、Carthageでライブラリを導入しました。

github "ephread/Instructions" ~> 2.0

まずは、コーチマークを表示するところ

実装は、Instructionsのリポジトリにもサンプルがあったので、そちらを参考にしながら進めました。

CoachMarksControllerのdataSourceを実装して、
coachMarksController.start(in: )を呼んであげるだけでコーチマークを表示できました(⌒ω⌒)

今回は、コーチマークのターゲットがTableViewCellなので、事前にIndexPathを指定して、
spotlightTargetViewにcellを保持するように実装してみました。

ViewController.swift(初期設定)
    // コーチマークの初期設定
    private func setupCoachMarksController() {
        self.coachMarksController.dataSource = self

        // オーバーレイをタップでもコーチマークを閉じれるようにする
        self.coachMarksController.overlay.isUserInteractionEnabled = true
        // コーチマークの背景色を設定
        self.coachMarksController.overlay.backgroundColor = UIColor.black.withAlphaComponent(0.5)
    }

    /// コーチマークを表示する
    private func startCoachMarks() {
        let indexPath = IndexPath(row: 0, section: 0)

        // [section, row] = [0, 0]のCellがあれば、コーチマークを表示する
        if tableView.numberOfRows(inSection: indexPath.section) > indexPath.row, let cell = tableView.cellForRow(at: indexPath) {
            self.spotlightTargetView = cell
            self.coachMarksController.start(in: .currentWindow(of: self))
        }
    }

CoachMarksControllerのdataSourceの実装はこんな感じでシンプル

ViewController.swift(CoachMarksControllerDataSource実装部)
extension ViewController: CoachMarksControllerDataSource {
    func numberOfCoachMarks(for coachMarksController: CoachMarksController) -> Int {
        return 1
    }

    func coachMarksController(_ coachMarksController: CoachMarksController, coachMarkAt index: Int) -> CoachMark {
        // 吹き出しを表示する対象のビューを指定する
        return coachMarksController.helper.makeCoachMark(for: spotlightTargetView)
    }

    func coachMarksController(_ coachMarksController: CoachMarksController,
                              coachMarkViewsAt index: Int,
                              madeFrom coachMark: CoachMark) -> (bodyView: (UIView & CoachMarkBodyView), arrowView: (UIView & CoachMarkArrowView)?) {

        let coachViews = coachMarksController.helper.makeDefaultCoachViews(withArrow: true,
                                                                           withNextText: false,
                                                                           arrowOrientation: coachMark.arrowOrientation)
        coachViews.bodyView.hintLabel.text = "スワイプでお気に入りから削除できます"
        return (bodyView: coachViews.bodyView, arrowView: coachViews.arrowView)
    }
}

ここまでで、このような感じなりました!
sample1.png

この状態だと、まだ分かりづらいかなーと思うので、アニメーションを加えていきます。

スワイプで削除風のアニメーションを実装

スワイプで削除するようなアニメーションを実装します。

アニメーションは、Stack Overflowの投稿をパクらせて参考にさせていただきましたm(_ _)m
UITableView invoke swipe actions programmatically

参考情報そのままだと少し使いづらいところがあったので、
アニメーション完了後の処理をクロージャで実装できるようにしています。

動作

アニメーションを加えたら、いい感じになりました(^-^)v
(Gifの問題で、「削除」ラベルの色が実際と少し違っています。)

sample2.gif

完成したコード

以下、アニメーション完了後からオーバーレイのタップを許可するなどの微調整をした最終的なソースコードです。
(コーチマーク表示済みかどうかの判定は、UserDefaultsなどで実現できると思うので、省いています。)

ViewController.swift
import UIKit
import Instructions

final class ViewController: UIViewController {

    private let coachMarksController = CoachMarksController()

    // コーチマークでスポットライトが当たるView
    private var spotlightTargetView: UIView!
    private var spotlightTargetIndexPath: IndexPath?

    private var items = ["apple", "banana", "cherry"]

    @IBOutlet private weak var tableView: UITableView! {
        didSet {
            tableView.dataSource = self
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        self.setupCoachMarksController()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        self.navigationItem.title = "お気に入り一覧"
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        self.startCoachMarks()
    }

    private func setupCoachMarksController() {
        self.coachMarksController.dataSource = self
        self.coachMarksController.delegate = self

        // コーチマークの背景色を設定
        self.coachMarksController.overlay.backgroundColor = UIColor.black.withAlphaComponent(0.5)
    }

    /// コーチマークを表示する
    private func startCoachMarks() {
        let indexPath = IndexPath(row: 0, section: 0)

        // [section, row] = [0, 0]のCellがあれば、コーチマークを表示する
        if tableView.numberOfRows(inSection: indexPath.section) > indexPath.row, let cell = tableView.cellForRow(at: indexPath) {
            self.spotlightTargetView = cell
            self.spotlightTargetIndexPath = indexPath
            self.coachMarksController.start(in: .currentWindow(of: self))
        }
    }
}

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

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") else {
            fatalError("Cell is nil.")
        }
        cell.textLabel?.text = items[indexPath.row]
        return cell
    }

    func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        return true
    }

    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
        if editingStyle == .delete {
            self.items.remove(at: indexPath.row)
            tableView.deleteRows(at: [indexPath], with: .automatic)
        }
    }
}

extension ViewController: CoachMarksControllerDataSource {
    func numberOfCoachMarks(for coachMarksController: CoachMarksController) -> Int {
        return 1
    }

    func coachMarksController(_ coachMarksController: CoachMarksController, coachMarkAt index: Int) -> CoachMark {
        // 吹き出しを表示する対象のビューを指定する
        return coachMarksController.helper.makeCoachMark(for: spotlightTargetView)
    }

    func coachMarksController(_ coachMarksController: CoachMarksController,
                              coachMarkViewsAt index: Int,
                              madeFrom coachMark: CoachMark) -> (bodyView: (UIView & CoachMarkBodyView), arrowView: (UIView & CoachMarkArrowView)?) {

        let coachViews = coachMarksController.helper.makeDefaultCoachViews(withArrow: true,
                                                                           withNextText: false,
                                                                           arrowOrientation: coachMark.arrowOrientation)
        coachViews.bodyView.hintLabel.text = "スワイプでお気に入りから削除できます"
        return (bodyView: coachViews.bodyView, arrowView: coachViews.arrowView)
    }
}

extension ViewController: CoachMarksControllerDelegate {

    func coachMarksController(_ coachMarksController: CoachMarksController,
                              didShow coachMark: CoachMark,
                              afterChanging change: ConfigurationChange,
                              at index: Int) {

        guard let targetIndexPath = self.spotlightTargetIndexPath else { return }
        UIView.animateRevealHideActionForRow(tableView: self.tableView, indexPath: targetIndexPath) { [weak self] in
            // アニメーション完了後、オーバーレイをタップでもコーチマークを閉じれるようにする
            self?.coachMarksController.overlay.isUserInteractionEnabled = true
        }
    }
}
UIView+.swift
import UIKit

extension UIView {

    /// TableViewのスワイプアクションの擬似的なアニメーション
    class func animateRevealHideActionForRow(tableView: UITableView, indexPath: IndexPath, completion: (() -> Void)? = nil) {
        guard let cell = tableView.cellForRow(at: indexPath) else { return }

        let swipeLabelWidth = UIScreen.main.bounds.width / 2
        let swipeLabelFrame = CGRect(x: cell.bounds.size.width, y: 0, width: swipeLabelWidth, height: cell.bounds.size.height)
        var swipeLabel: UILabel? = .init(frame: swipeLabelFrame)
        swipeLabel?.text = "  削除"
        swipeLabel?.backgroundColor = .red
        swipeLabel?.textColor = .white
        cell.addSubview(swipeLabel!)

        UIView.animate(withDuration: 0.5, animations: {
            cell.frame = .init(x: cell.frame.origin.x - swipeLabelWidth / 2,
                               y: cell.frame.origin.y,
                               width: cell.bounds.size.width + swipeLabelWidth / 2,
                               height: cell.bounds.size.height)
        }) { finished in
            UIView.animate(withDuration: 0.5, animations: {
                cell.frame = .init(x: cell.frame.origin.x + swipeLabelWidth / 2,
                                   y: cell.frame.origin.y,
                                   width: cell.bounds.size.width - swipeLabelWidth / 2,
                                   height: cell.bounds.size.height)
            }, completion: { finished in
                swipeLabel?.removeFromSuperview()
                swipeLabel = nil

                completion?()
            })
        }
    }
}

さいごに

コーチマークでテキストを添えるだけでも親切だけど、動きをつけるとより親切かなと思いました!
(やり過ぎると、しつこいですけどね・・・)

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