20200801のSwiftに関する記事は13件です。

WebViewの表示方法

#WebViewをサクッと表示!!

まず、ViewController.fileにWebKitをimportします。

ViewController.swift
import UIKit
import WebKit

class ViewController: UIViewController {
    @IBOutlet weak var webView: WKWebView!

    override func viewDidAppear(_ animated: Bool){
        }
    } 

次に、main.storyboardへ。
WebKit Viewを右上の「+」 ボタンから選択し、ViewControllerへ貼り付け。

スクリーンショット 2020-08-01 21.04.34.png

次にwebViewを表示させるコードを書きます。

ViewController.swift
import UIKit
import WebKit

class ViewController: UIViewController {
    @IBOutlet weak var webView: WKWebView!
    var topPadding:CGFloat = 0

    override func viewDidAppear(_ animated: Bool){
        print("viewDidAppear")

        if #available(iOS 11.0, *) {
            // 'keyWindow' was deprecated in iOS 13.0: Should not be used for applications
            let window = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
            topPadding = window!.safeAreaInsets.top
        }

        let webUrl = URL(string: "https://www.google.com/")!
        let myRequest = URLRequest(url: webUrl)
        webView.load(myRequest)

        // インスタンスをビューに追加
        self.view.addSubview(webView)
}

これでオッケーです!
ただ、これでシュミレーターを立ち上げると・・・

スクリーンショット 2020-08-01 21.20.41.png
この様に、エラーが出てしまいます。
どうやら原因はフレームワークが追加されていないからとのこと。
ということで、追加。
スクリーンショット 2020-08-01 21.03.11.png

これで完成です!
webViewを表示するのは非常に簡単ですね!
ビューアーなどの記事サイトを表示させる時に活躍しそうですね。
webkitViewの使用方法でした!ありがとうございました。
            スクリーンショット 2020-08-01 21.25.19.png

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

Swiftの実機テストする際に出たエラーの解決法

はじめに

いつもはSimulatorを使ってテストをしているのですが、自分のiPhoneでも試してみたいと思い、実機テストをやってみました。思っていたより梃子摺ったので遭遇したエラーの解決方法をまとめてみました。

「Signing for "アプリ名" requires a development team.」というエラーが出た場合

Signing & CapabilitiesでTeamを設定する。Apple IDでログインするとTeamという項目で自分のアカウントを選択できるようになるのでそこから設定する。
スクリーンショット 2020-08-01 20.39.24.png

「Could not locate device support files.」というエラーが出た場合

https://github.com/filsv/iPhoneOSDeviceSupport
こちらのサイトから自分のiPhoneのiOSにあったファイルをダウンロードする。
Finderでcommand + shift + gを押すと、パスを指定して移動できるので、下のパスをコピペする。

/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/

開いたフォルダに先程Githubからダウンロードしたフォルダを移動させて、Xcodeを再起動する。
(もし13.5.1のようにバージョンが細かい場合は、Githubからダウンロードした13.5のファイル名を13.5.1のように変更すれば良い。)

「Untrusted Developer」というエラーが出た場合

iPhoneで設定→General→Profile & Device Managementに移動すると、Developer Appという項目があるので、そこにある自分のアプリ名をクリックし、「<アプリ名>を信頼する」で「信頼」というボタンを押せば、自分のiPhoneで自作したアプリにアクセスできるようになります。

参考にしたサイト
https://qiita.com/solabito331/items/17ee51d954fb3f87b37c
https://cpoint-lab.co.jp/article/201906/10350/
https://qiita.com/segur/items/bef54efa7764885173bb

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

【Swift】AtCoderをやっていくー (AtCoder Beginners Selection編)

前提

何を書いているか

基本的にAtCoderのお題と回答を書いていく予定です。

注意

回答等も載せていくので、自力で解きたい人はネタバレになってしまうので、気をつけてください。

あと、筆者は競プロ初心者です。
早く解くというよりは、書き方の勉強としてやっていきます。
より良い書き方があった場合はコメントいただけると嬉しいです!
また、競プロの観点から「こういう書き方がよい」というのもあれば、それもコメントいただけると助かります。

AtCoderをやる理由、Qiitaに投稿する理由

Swiftだけでなく、プログラミング自体初心者なので、
AtCoderを通して良いコードの書き方を学習する。
Qiitaに解説としてアウトプットすることで、理解を深める。

参考

下記サイトに感化されて初めてみました。
回答も参考にさせていただいております。
[AtCoder]Swiftでも競プロがしたい!

問題文はAtCoderから引用しています。
AtCoder

それではやっていくー

practice contest

まずは練習用のコンテストから

A - Welcome to AtCoder

  • 回答時間:未計測
  • 得点:100/100
  • 問題

    問題文
    高橋君はデータの加工が行いたいです。
    整数 a,b,cと、文字列 s が与えられます。
    a+b+c の計算結果と、文字列 s を並べて表示しなさい。
    制約
    1≤a,b,c≤1,000
    1≤|s|≤100
    入力
    a
    b c
    s
    出力
    a+b+c と s を空白区切りで 1行に出力せよ。

    AtCoderWebサイトより引用

  • 回答

let a = Int(readLine()!)!
//整数bとcを取得→半角スペースで配列に分割→map関数でIntにキャスト
let bc = readLine()!.split(separator: " ").map{ Int($0)! }
let s = readLine()!

let sum = a + bc[0] + bc[1]

print(sum,s)

AtCoder Beginners Selection

初心者向け問題集

ABC086A - Product

  • 回答時間:3分54秒
  • 得点:100/100
  • 問題

    問題文
    シカのAtCoDeerくんは二つの正整数 a,b を見つけました。
    a とb の積が偶数か奇数か判定してください。
    制約
    1≤a,b≤10000
    a,b は整数
    入力
    入力は以下の形式で標準入力から与えられる。
    a b
    出力
    積が奇数なら Odd と、 偶数なら Even と出力せよ。

    AtCoderWebサイトより引用

  • 回答

let ab = readLine()!.split(separator: " ").map { Int($0)! }
let result = ab[0] * ab[1]

//余りが0なら偶数
if result%2 == 0 {
    print("Even")
} else {
    print("Odd")
}
  • より良い回答を目指して
    • if文の分岐箇所で三項演算子とisMultipleメソッドの活用
print(result.isMultiple(of: 2) ? "Even" : "Odd")

ABC081A - Placing Marbles

  • 回答時間:19分40秒
  • 得点:100/100
  • 問題

問題文
すぬけ君は 1,2,3 の番号がついた 3 つのマスからなるマス目を持っています。 各マスには 0 か 1 が書かれており、マス i には si が書かれています。
すぬけ君は 1 が書かれたマスにビー玉を置きます。 ビー玉が置かれるマスがいくつあるか求めてください。
制約
s1,s2,s3 は 1 あるいは 0
入力
入力は以下の形式で標準入力から与えられる。
s1s2s3
出力
答えを出力せよ。

AtCoderWebサイトより引用

  • 回答

いろいろやり方考えたけど、全く思い付かず
とりあえずforEachで回すことに。。。

let sss = readLine()!
var count = 0
sss.forEach {
    if $0 == "1" {
        count += 1
    }
}
print(count)
  • より良い回答を目指して
    • forEach文からPrintまでをreduce関数で代用
print(sss.reduce(0) { $0 + Int(String($1))! })

続きの問題はまた後日やったときにあげます。

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

iPhone&iPad 画面サイズ早見表

Xcode version 11.5で動作するiPhoneとiPadの画面サイズの早見表です。

デザインを考えるときに使っていただけると幸いです。

画面サイズ取得方法

ViewController.swift
import UIKit
class ViewController: UIViewController {
    let width = UIScreen.main.bounds.size.width   //画面の横幅を取得
    let height = UIScreen.main.bounds.size.height //画面の縦幅を取得
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        print(width)
        print(height)
    }
}

iPhoneシリーズ

SE 11ProMax 11Pro 11 8Plus 8
width 375 414 375 414 414 375
height 667 896 812 896 736 667

iPadシリーズ

Pro 12.9-in. Pro 11-in. Pro 9.7-in. Air 7th 無印
width 1024 834 768 834 810
height 1136 1194 1024 1112 1080

参考文献

https://www.yukiiworks.com/archives/118

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

selfって書いたり書かなかったりすることない???

以前働いていた会社ではソースコードで絶対にselfをつけていたのに、ウェブで読むソースコードではほとんどselfがついてないことが多い。たまにエラーが出るからつけときましょう、っていうのが多い。

なんで?つけるのつけないのどっち???

下記サイトからわかりやすい文章を参照。
https://medium.com/@muukii/swift-%E3%83%A1%E3%83%B3%E3%83%90%E5%A4%89%E6%95%B0%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E6%99%82%E3%81%ABself%E3%81%AF%E6%9B%B8%E3%81%8F%E3%81%B9%E3%81%8D-7a1b1069bf9d

Swiftはselfを書かなくてもメンバ変数にアクセスが可能です。
ただ、ローカル変数と衝突した際にはselfを付ける必要があります。

なるほど〜〜〜。

上記サイトにもメリットデメリット載っており、意見を書かれているので、ここでの結論としては、

Xcodeに怒られたらつけとこ〜〜〜?⭐️?⭐️?⭐️

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

clipToBoundsとは

アイコン画像を丸くするときなどに、

    self.iconImageView.layer.cornerRadius = self.iconImageView.frame.size.width * 0.5
    self.iconImageView.clipsToBounds = true

と書いた時の疑問。
cornerRadiusは角丸にするためのコードだと理解できるけど、その下のclipsToBoundsってなんでいつもtrueにせんとあかんのや、と。

調べて出てきたのは、clipsToBoundsの特徴をまとめた下記URL。
https://qiita.com/orimomo/items/7075fb911da5c9d2fba5

UIView(+それを継承しているUIImageView等)のプロパティである
Viewにセットしたコンテンツが、領域boundsの外を描画するかどうかを決定する
デフォルト値がfalseで、trueにすると領域内に限定される

よくわからない・・・

と思い、下に読み進めていくと、わかりやすい画像が載っていた。
ここで記載するのは割愛しますが、わかりやすくいうと、imageViewを配置して画像をセットしたとき、
false: 画像がはみ出した状態で出力
true: 画像をimageView内に収める
って感じです。

つまり、画像の角の数値を決めたりとかするためにclipsToBoundsをtrueに定義しているわけではなく、丸いimageViewを決めた後に、アイコンをセットした際、その枠内に当て嵌めるようにしてるんですね。ナットクトクコさん。

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

全く需要が無さそうだがSwiftUIでヘブライ文字を覚えるiOSアプリを作った

はじめに

iOSアプリ作りたいという人の精神的な手助けになったらいいなと思って書きます。というのは、アプリを作るということの全体像を描くのに意味があるのではと考えた次第です。なので細かいことはそこそこにして、完成までに何をやったかを一通り書きたいと思います。

できたもの

ヘブライ文字の暗記クイズアプリ
https://github.com/tomita28/alephbeth
https://apps.apple.com/jp/app/%E3%83%98%E3%83%96%E3%83%A9%E3%82%A4%E6%96%87%E5%AD%97/id1512330663?l=en

動機

  • 最近プログラム書いてないなあ。なんか書きたいなあ。
  • 日本語でヘブライ語勉強するアプリ誰も作ってへんやないか。
  • SwiftUIなら簡単にアプリが作れるらしい!(本当に?)
  • ところで知り合いがヘブライ語勉強したいらしいがヘブライ文字暗記アプリがいいのないな。
  • ないものは作るしかない♪ https://www.youtube.com/watch?v=6zr6pWwHACU

リリースまでにやったこと

  • SwiftUIのチュートリアルをやった。
  • ヘブライ文字のラテンアルファベット転写について調べた。
  • 作りながら仕様を考えた。
  • XCodeでコードを書いた。(ここまでで三日くらい(大変))
  • kritaでiconを描いた。(これに一日(大変))
  • プライバシーポリシーの設置
  • Googleのバナーを貼った
  • DeployGateでテスト及びリリース作業をした。(これに一日(大変))
  • いろいろ変更点が出てきてもう何がなんだか。(あれから何ヶ月たったろう)

詳しい話

SwiftUIのチュートリアル

 よくチュートリアルを終えると完全に理解した気になるっていうけど、私みたいな初級者にとってはチュートリアルを最後までやり切る勤勉さというのが本当に必要なんだなって思いました。新しい概念やそもそも知らない概念が出てくるときに、一番理解できる可能性が高いのは結局チュートリアルのなかであって、それらを解説してくれる誰かの説明は、あくまで自分でもチュートリアルをやったあとで効いてくるのだなというのが正直な感想でした。
 とはいえ、自分のアプリに必要なものでいうと全部をやる必要もなかったので、SwiftUI TutoarlのEssentialsというところまでは最低やった方がいいと思いました。

公式 https://developer.apple.com/tutorials/swiftui/creating-and-combining-views

大事だった概念

すいません、私には厳密な説明ができないのでざっくりした"気持ち"の部分だけ。

SwiftUIとView

従来のアプリの画面の作り方と異なり(やったことないけど)、ViewというObjectをコード上に書いていくことが、そのまま画面の配置になる。正直こういう仕組みでなければ自分は最後までこのアプリ作ろうと思えなかったと思う。画面のデザインをドラッグしていじったりというのはどうもうまく想像できない。

@State

Viewの中で随時変更できる値を保持している

@ObservedObject

Viewをまたいで保持可能だが、新たなインスタンスを作るごとに新しいデータが保持される。このアプリではネストしていくクイズの不正答のリストにあたる。

@EnvironmentObject

アプリ全体を通して保持して欲しいデータ。このアプリではユーザー設定の部分。

ヘブライ文字のラテンアルファベット転写方式

ヘブライ文字というのは広義のアルファベット一種であり(その源流と言ってもいい)、אבגדと言った文字のことです。これを覚えるためには例えばא(alef)と言ったように、英語にも使われているラテンアルファベットで表記するのが一番手取り早い方法です。しかし、ラテンアルファベット自体は世界共通の発音体系なわけではありません。また、ヘブライ語の全ての発音を網羅できているわけでもありません。そこで、いくつかの流儀によってヘブライ文字をラテンアルファベットに置き換える(転写する)方式を取らねばなりません。そこには恣意性があり、歴史性があります。最初のバージョンではイスラエルでよく見かける方式に統一していたのですが、某先生からある種の聖書(古典)ヘブライ語転写方式にも対応して欲しいと言われて、いろいろ教科書をひっぱり出しておりました。

転写方式

  • Hebrew Academy
  • Thomas O Lambdin

仕様を考える

プログラマをしていた時期が少しだけありましたが、ここまで自由に自分で仕様を考えることはありませんでした。結局仕様は作りながら考えるのが早かった。幸い、SwiftUIはPreviewsという概念のおかげで、Viewのコードを書いたそのすぐ下に、テストになるもの(具体的な値を代入した時のViewクラスの挙動を確認する仕組み)があるので、ほとんどテストコードを同時にかけるのでめちゃ便利でした。逆にこのPreviewsの機能を誤解していたせいで後述のNavigationViewを画面一つ一つに書かなければならないと思ってしまったところがあります。NavigationViewの子要素ではNavigationLinkの挙動を直接確認できないというのがPreviewsの仕様だと自分では納得しております。
で、結局仕様ですが、

  • ヘブライ文字子音の呼称一覧
  • 母音記号の呼称一覧
  • 文字(子音、母音両方)クイズ
  • 不正答の文字を一覧で再度表示する
  • 不正答の文字だけをクイズする
  • 再度不正答の文字について何層でもクイズ、一覧表示できるようにする。
  • ラテンアルファベット転写方式を最初の画面で選択できるようにする。

となりました。

XCodeで頑張った

ここでは簡単にお世話になった概念を紹介するのみにします。

NavigationView

矢印をタップするとどんどん次の画面が開きます(iPhoneの設定画面みたいなやつ)
大事なことですがNavigationLinkを貼るのだけはたくさんやってよくて、NavigaitonViewを設置し直すと、目次のバーが重複します。このような使い方はあまりないと思いますので、通常は大元のViewの中に(例えばContentViewの直下に)NavigationViewを設置し、その下は全てNavigationLinkを貼るだけにしてください。

MainView.swift
import SwiftUI

struct MainView: View {
    @EnvironmentObject var userData: UserData
    @State var showingSetting = false

    var body: some View {
        VStack{
            NavigationView{
                List{
                    HStack{
                        Spacer()
                        Text("メニューを選んでね")
                        .fontWeight(.thin)
                    }
                    NavigationLink(destination: ContentView(
                            letters: lettersData[0].letters,
                            pickers: lettersData[0].letters,
                            title: "ヘブライ文字クイズ"
                            ))
                            ...
ContentView.swift
import SwiftUI

struct ContentView: View {
    var ...

    var body: some View {
        VStack {
            ...
            Spacer()
            HStack{
                NavigationLink(
                    destination: ResultView(
                        quizData: quizData,
                        withUnderScores: self.withUnderScores,
                        questionAmount: self.questionedLetters?.count,
                        letters: letters,
                        pickers: pickers,
                        percent: self.completedRate()
                    )
                    .environmentObject(userData),
                    isActive: $goResultView) {
                    Text("")
                }
                ...

Alert

AlertからNavigationLinkを使う方法が面倒かった。

ContentView.swift
NavigationLink(
    destination: ResultView(
        quizData: quizData,
        withUnderScores: self.withUnderScores,
        questionAmount: self.questionedLetters?.count,
        letters: letters,
        pickers: pickers,
        percent: self.completedRate()
    )
    .environmentObject(userData),
    isActive: $goResultView) {
    Text("")
}
Button("結果を見る"){
    if(self.quizData.unQuestionedLetters.count > 0){
        self.showingUnfinishedAlert = true
    } else {
        self.goResultView = true
    }
}.alert(isPresented: $showingUnfinishedAlert) {
    Alert(title: Text("未終了"), 
    message: Text("まだ全ての問題に回答していません。このクイズを終了して結果を見ますか?"),
    primaryButton: .destructive(Text("結果を見る")) {
        self.goResultView = true
        }, 
    secondaryButton: .cancel())
}

カスタムフォント

今回ヘブライ文字の筆記体を表示する必要があったので、フォントを使いしました。info.plistを編集する必要があるので注意してください。

既知の問題

筆記体のヘブライ文字はイタリックの文字のように右に傾いており、上下に幅の広い文字の場合、右上と左下に大きく伸びます。これが表示上左右の出っ張りが切れて見えなくなるという問題があります。ちなみに左右にスペースを入れても直りません。今回解決できなかったので、左右に_を入れて対処しました。

Screen Shot 2020-08-01 at 13.19.09.png
これがアレフ。

Screen Shot 2020-08-01 at 13.19.49.png
ちょっと右が切れてるのわかります?

Screen Shot 2020-08-01 at 13.21.33.png
これがギメル

Screen Shot 2020-08-01 at 13.21.07.png
あー右が切れた。

LetterExplanation.swift
ScrollView{
    Text("いいから覚えるんだ")
        .padding()
    if(withUnderScores ?? true){
        Text("左右の横線(アンダースコア)を文字の高さの基準にしてください。")
            .padding()
    }
    self.displayFont(text: Text(self.textWithUnderScores(string: letter.script)), name: "活字体")
    if(!(letter.dagesh ?? true)){
        self.displayFont(text: Text(self.textWithUnderScores(string: letter.script))
            .font(.custom("KtavYadCLM-BoldItalic", size: 150))
        , name:"筆記体")

    }

...

func textWithUnderScores(string: String) -> String {
    if (self.withUnderScores ?? true ) {
        return "_" + string + "_"
    }else{
        return string
    }
}

この_をとったらこの現象がおこると理解していただければ。いやあ、どうしたらいいんだろ。

SheetView

したから上にスッと出てくる画面ですね。設定画面で使いました。意外と面倒。

ContentView.swift
Button(action: {
    self.showingSetting.toggle()
}) {
    Image(systemName: "gear").imageScale(.large)
}.sheet(isPresented: $showingSetting) {
    SettingView(
        showSheetView: self.$showingSetting// userData: self.userData
    )
    .environmentObject(self.userData)
}
SettingView.swift
import SwiftUI

struct SettingView: View {

    @Binding var showSheetView: Bool
    @EnvironmentObject var userData: UserData

    var body: some View {
        NavigationView {
            Form {
                Picker(
                    selection: $userData.transliterationMode,
                label: Text("ラテン文字転写の方法"))
                {
                    ForEach(
                    TransliterationMode
                        .allCases
                        .filter{switch $0 {
                            case TransliterationMode.Common: return false
                            default: return true
                            }}
                    , id: \.self) {
                        Text($0.rawValue).tag($0)
                    }
                }
            }
            .navigationBarTitle(Text("設定"), displayMode: .inline)
            .navigationBarItems(trailing:
                Button(action: {
                    print("Dismissing sheet view...")
                    self.showSheetView = false
                })
                {
                    Text ("完了")
                }
            )
        }
    }
}

kritaでアイコンを作ろう!

自分一人でアプリ作ろうとしたらアイコンも自作か...まじめんどくさいな。いろいろソフトあるみたいですがkritaというのをインストールしました。大したことはしてないのですが。この辺は気合ですね。デザインに死ぬほど自信がないので他人に見てもらったりしました。

プライバシーポリシーの設置

最近は個人の開発者でもプライバシーポリシーを設置することを求められるそうです。というかリリース作業の途中にめっちゃAppleに念押しされました。というわけでGitHub上にサイトを設置し、そこへのリンクを貼っておきました。今のところこれでBanとかはないです(2020/7)。

バナーをはろう!

正直全く儲かる気がしないのだけど、それでも練習と思ってGADBannerというのを貼りました。

DeployGateは全てを解決する!

他人にテストしてもらったり、そもそもリリースとかバージョンアップとか、DeployGateめっちゃ便利。
そもそもどうやったらApple Storeにアップできるのか全然わからない状況においてDeployGateのマニュアルは非常に優秀だった。

リリース作業

実はここで一番ハマったのは「アプリ紹介用のスクショを貼る」という作業。simulatorでスクショしても全然サイズ合わへんヤンけ!
そもそもsimulatorはpixelを合わせて画面上に表示される(よくわかってない)。一応windowのタブからリアルなサイズに合わせることもできるようだが、それでも必要なサイズにはならない。結局無理やりリサイズした。なんかスマートな方法はないものか。

その後

某先生からの指摘によりユーザー設定で転写方式を変えるためにいろいろしました。そのへんを含めてXCodeのところには書いておきました。

感想

実際にやってみるっていうのは一番楽しいことであって、採算とか目的とかはある程度度外視して、このアプリ作ってみて本当に楽しかった。出来上がったらいつもお世話になってるqiitaになんか書こうと思ってたのですが、いろいろ引っ張ってきてたリンクをもうたどることができない...。みんなどうやって記事書いてるんだ。作りながら書いてる? 今度からは記事を書きながら作業するのが目標になりそう。

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

Swiftの!と?に関して、まとめてみた

!と?の違いが全くわからん。。。と思いまして、、

自分なりに調べてまとめてみました。

違っていたら、教えていただけるとありがたいです。

SwiftやFlutterをかまっているのですが、

Swiftの大切概念のオプショナル型についてまとめてみようと思います。

まず、オプショナル型とは、nilを許容しない形のことです
そのため、pythonでしたら、
Str型にnilが入っていても問題なかったのですが、Swiftでは、それが許されません。
(これがなかなか慣れなかった。。?)

そのため、

?がついていると、nilを認める形になります。

?がついていないと、nilを認めません

だったら、!はなんだという話になりますよね?

!はnilが入っていたら、Errorを吐き出します。

そのためnilが入っているかを!一文字で判別する事ができます。

以上です!
最後まで読んでいただき、ありがとうございました!!

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

TAYLOR SWIFT THE WOOD MERCH - IN THE TREE HOODIE, T-SHIRT

TAYLOR SWIFT FOLKLORE ALBUM 'IN THE TREE' T-SHIRT

TAYLOR SWIFT THE WOOD SHIRT

TAYLOR SWIFT THE WOOD HOODIE

Taylor Swift’s ‘Folklore’ T-shirt

Taylor Swift Folklore T-shirt

Taylor Swift Folklore Merch

Taylor Swift Folklore Hoodie

TAYLOR SWIFT IN THE TREE T-SHIRT

TAYLOR SWIFT THE WOOD MERCH

TAYLOR SWIFT THE WOOD MERCH

taylor-swift-the-wood-merch.jpg

TAYLOR SWIFT IN THE TREE T-SHIRT, HOODIE IN BLACK WHITE COLOR
Taylor Swift The Wood | Taylor Swift In The Tree
Folklore-Merchandise.jpg

TAYLOR SWIFT'S 'FOLKLORE' MIGHT BE THE BEST ALBUM OF HER ENTIRE CAREER
Taylor Swift released her eighth studio album, "Folklore," on Friday.Swift surprised fans by announcing its release just one day in advance — and less than one year after the release of her acclaimed seventh album "Lover.""Most of the things I had planned this summer didn't end up happening, but there is something I had planned that DID happen," she wrote on social media. "And that thing is my 8th studio album, folklore. Surprise!"She described "Folklore," stylized in all lowercase, as "an entire brand new album of songs I've poured all of my whims, dreams, fears, and musings into."

TAYLOR SWIFT’S ‘FOLKLORE’ SELLS 1.3 MILLION COPIES IN 24 HOURS
Even though its existence was announced just 15 hours before its release, Taylor Swift’s “Folklore” sold more than 1.3 million copies globally in just 24 hours, according to Republic Records, which released the album.According to the announcement, the album also broke the global record for first-day album streams on Spotify by a female artist with 80.6 million streams, and delivered “the most-streamed pop album on Apple Music in 24 hours” with 35.47 million streams. “Folklore” also set the U.S. and Worldwide Amazon Music Indie/Alternative Streaming Record, although further details were not immediately available.Final first-week numbers will not be available until a week from Monday, but the album could well be on track for the biggest debut of 2020, a mark held by The Weeknd’s “After Hours” until last week, when it was surpassed by Juice WRLD’s posthumous album “Legends Never Die,” which clocked 517,800 album-equivalent units in its first week — the first album to shift more than 500,000 units in its first week this year, according to Rolling Stone’s album charts. “After Hours” debuted with 460,000 units in March. (To put that in context, the above numbers are U.S. only, while Swift’s numbers provided by the label are global.)

TAGS#

Taylor Swift’s ‘Folklore’ T-shirt

Taylor Swift Folklore T-shirt

Taylor Swift Folklore Merch

Taylor Swift Folklore Hoodie
taylor-swift-the-wood-Tee.png
 SHOP NOW 

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

【Swift】ゼロからのCombineフレームワーク - とりあえずViewにデータバインディングしたいための人の最小実装

意外と難しかったCombine

RxSwiftならある程度使えるし、簡単に使えるようになるかな?と思っていました。
しかし、いざ試してみるとなかなか苦労したので、まずは普段の開発に取り入れられる部分から切り出してみました。

Viewに値をバインドする最小実装 UIKit版

import Combine
import UIKit

class ViewModel {
    @Published var labelText: String = "Default value."
}

class ViewController: UIViewController {
    var label: UILabel! // 適当な場所(storyboard, viewDidLoadなど)で初期化する
    let viewModel = ViewModel()

    private var cancellables = Set<AnyCancellable>()

    override func viewDidLoad() {
        super.viewDidLoad()

        viewModel.$labelText
            .map({ Optional($0) })
            .receive(on: DispatchQueue.main)
            .assign(to: \UILabel.text, on: label)
            .store(in: &cancellables)
    }
}

適当なタイミングで、viewModel.labelText = "Hello!"などと値を変更すると、自動的にUILabelが更新されます。

解説

@PublishedPublisherプロトコル

バインドしたいプロパティの変更を監視するために、import Combineしたうえで、@PublishedというProperty Wrapperをバインドしたいプロパティに付与します。

ViewModel
class ViewModel {
    @Published var labelText: String = "Default value."
}

Property Wrapperを付与したプロパティをもつクラスには、自動的に$labelTextのようにプロパティ名の先頭に$がついたgetterが生成されます。@Publishedを付与した場合、このgetterはPublished<Output>.Publisher型になります。

Publisherというのが監視される側のプロトコルです(RxSwiftならObservable)。また、この場合Output = Stringです。

バインド

Publisherに準拠したプロパティをUIViewにバインドするには、assignメソッドを使います。

viewModel.$labelText
    .map({ Optional($0) })
    .receive(on: DispatchQueue.main)
    .assign(to: \UILabel.text, on: label)
    .store(in: &cancellables)

assign

assignメソッドの定義は次のようになっています。

public func assign<Root>(to keyPath: ReferenceWritableKeyPath<Root, Self.Output>, on object: Root) -> AnyCancellable

keyPathには\UILabel.text1のようにバインド先のUIViewの型名とそのプロパティ名を記載します。

assignメソッドはAnyCancellableというCancellableプロトコルに準拠したクラスのインスタンスを返します。このインスタンスのcancelメソッドを呼ぶことでバインド(監視)が解除されます。

また、AnyCancellableのインスタンスはメモリから解放されるタイミングでもcancelメソッドを呼んでバインドを解除するようです2。そのため、ViewControllerSet<AnyCancellable>型のプロパティを持たせて参照を保持します。追加する際にチェーンでメソッドを呼べるようにstoreメソッドが用意されています。

map

Publisherには様々なオペレーターが用意されており、監視している値に変更を加えたり、流れてくる時間や回数などの条件によって流れをせきとめたりすることができます。

mapはもっとも基本的なオペレーターで、流れてきた値を加工することができます。
ここでは、UILabel.text: String?の型に合わせて、ViewModel.labelText: StringOptional型に変換しています。

receive(on: DispatchQueue.main)

receive(on:)はメソッドチェーンのうちで、このメソッド以降のチェーン内の処理が行われるスレッドを指定することができます。

assignメソッドはUIの更新処理にあたるので、メインスレッドを指定しています。

Viewに値をバインドする最小実装 SwiftUI版

import Combine
import SwiftUI

class ViewModel: ObservableObject {
    @Published var labelText: String = ""
}

struct ContentView: View {
    @ObservedObject private var viewModel = ViewModel()

    var body: some View {
        NavigationView {
            VStack {
                Text(viewModel.labelText)
                TextField("Title", text: $viewModel.labelText)
                    .multilineTextAlignment(.center)
            }
        }
    }
}

解説

@ObservedObject/ObservableObject

SwiftUIのViewにバインドするには、バインドしたいプロパティをもつviewModel@ObservedObjectを付与します。
ObservableObjectプロトコルに準拠させることで、@ObservedObjectが付与できるようになります。)

struct ContentView: View {
    @ObservedObject private var viewModel = ViewModel()
    ...
}

class ViewModel: ObservableObject {
    @Published var labelText: String = ""
}

バインド

var body: some View {
    NavigationView {
        VStack {
            Text(viewModel.labelText)
            TextField("Title", text: $viewModel.labelText)
                .multilineTextAlignment(.center)
        }
    }
}

@ObservedObjectを付与したプロパティはViewに監視されるようになり、値の変更があればUIが自動更新されます。
そのため、通常のString型を引数にとるクラスではviewModel.labelTextを渡すだけでバインド完了です。

@ObservedObjectによって生成された$viewModelプロパティのlabelTextBinding<String>という型を返します。これをBinding<String>型を引数にとるTextFieldに渡すことによって、双方向バインディングとなります。

こちらのSwiftUI版では、viewModel.labelTextの値を変更するとTextTextFieldの値が更新されますし、キーボードからTextFieldを変更しても、viewModel.labelText(とText)の値が更新されます。


  1. バックスラッシュはKey-Pathを表現するときの記法です。ドキュメントはこちら Key-Path Expression 

  2. ドキュメントに記述を見つけられなかったのですが、参照を保持しなかった場合はviewDidLoadを抜けた時点でcancelが呼ばれていました。 

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

【Swift】ゼロからのCombineフレームワーク - UIKitでデータバインディング

意外と難しかったCombine

RxSwiftならある程度使えるし、簡単に使えるようになるかな?と思っていました。
しかし、いざ試してみるとなかなか苦労したので、まずは普段の開発に取り入れられる部分から切り出してみました。

UIKitに値をバインドする

import Combine
import UIKit

class ViewModel {
    @Published var labelText: String = "Default value."
}

class ViewController: UIViewController {
    var label: UILabel! // 適当な場所(storyboard, viewDidLoadなど)で初期化する
    let viewModel = ViewModel()

    private var cancellables = Set<AnyCancellable>()

    override func viewDidLoad() {
        super.viewDidLoad()

        viewModel.$labelText
            .map({ Optional($0) })
            .receive(on: DispatchQueue.main)
            .assign(to: \UILabel.text, on: label)
            .store(in: &cancellables)
    }
}

適当なタイミングで、viewModel.labelText = "Hello!"などと値を変更すると、自動的にUILabelが更新されます。

解説

@PublishedPublisherプロトコル

バインドしたいプロパティの変更を監視するために、import Combineしたうえで、@PublishedというProperty Wrapperをバインドしたいプロパティに付与します。

ViewModel
class ViewModel {
    @Published var labelText: String = "Default value."
}

Property Wrapperを付与したプロパティをもつクラスには、自動的に$labelTextのようにプロパティ名の先頭に$がついたgetterが生成されます。@Publishedを付与した場合、このgetterはPublished<Output>.Publisher型になります。

Publisherというのが監視される側のプロトコルです(RxSwiftならObservable)。また、この場合Output = Stringです。

バインド

Publisherに準拠したプロパティをUIViewにバインドするには、assignメソッドを使います。

viewModel.$labelText
    .map({ Optional($0) })
    .receive(on: DispatchQueue.main)
    .assign(to: \UILabel.text, on: label)
    .store(in: &cancellables)

assign

assignメソッドの定義は次のようになっています。

public func assign<Root>(to keyPath: ReferenceWritableKeyPath<Root, Self.Output>, on object: Root) -> AnyCancellable

keyPathには\UILabel.text1のようにバインド先のUIViewの型名とそのプロパティ名を記載します。

assignメソッドはAnyCancellableというCancellableプロトコルに準拠したクラスのインスタンスを返します。このインスタンスのcancelメソッドを呼ぶことでバインド(監視)が解除されます。

また、AnyCancellableのインスタンスはメモリから解放されるタイミングでもcancelメソッドを呼んでバインドを解除するようです2。そのため、ViewControllerSet<AnyCancellable>型のプロパティを持たせて参照を保持します。追加する際にチェーンでメソッドを呼べるようにstoreメソッドが用意されています。

map

Publisherには様々なオペレーターが用意されており、監視している値に変更を加えたり、流れてくる時間や回数などの条件によって流れをせきとめたりすることができます。

mapはもっとも基本的なオペレーターで、流れてきた値を加工することができます。
ここでは、UILabel.text: String?の型に合わせて、ViewModel.labelText: StringOptional型に変換しています。

receive(on: DispatchQueue.main)

receive(on:)はメソッドチェーンのうちで、このメソッド以降のチェーン内の処理が行われるスレッドを指定することができます。

assignメソッドはUIの更新処理にあたるので、メインスレッドを指定しています。

おまけ:SwiftUI版

import Combine
import SwiftUI

class ViewModel: ObservableObject {
    @Published var labelText: String = ""
}

struct ContentView: View {
    @ObservedObject private var viewModel = ViewModel()

    var body: some View {
        NavigationView {
            VStack {
                Text(viewModel.labelText)
                TextField("Title", text: $viewModel.labelText)
                    .multilineTextAlignment(.center)
            }
        }
    }
}

解説

@ObservedObject/ObservableObject

SwiftUIのViewにバインドするには、バインドしたいプロパティをもつviewModel@ObservedObjectを付与します。
ObservableObjectプロトコルに準拠させることで、@ObservedObjectが付与できるようになります。)

struct ContentView: View {
    @ObservedObject private var viewModel = ViewModel()
    ...
}

class ViewModel: ObservableObject {
    @Published var labelText: String = ""
}

バインド

var body: some View {
    NavigationView {
        VStack {
            Text(viewModel.labelText)
            TextField("Title", text: $viewModel.labelText)
                .multilineTextAlignment(.center)
        }
    }
}

@ObservedObjectを付与したプロパティはViewに監視されるようになり、値の変更があればUIが自動更新されます。
そのため、通常のString型を引数にとるクラスではviewModel.labelTextを渡すだけでバインド完了です。

@ObservedObjectによって生成された$viewModelプロパティのlabelTextBinding<String>という型を返します。これをBinding<String>型を引数にとるTextFieldに渡すことによって、双方向バインディングとなります。

こちらのSwiftUI版では、viewModel.labelTextの値を変更するとTextTextFieldの値が更新されますし、キーボードからTextFieldを変更しても、viewModel.labelText(とText)の値が更新されます。


  1. バックスラッシュはKey-Pathを表現するときの記法です。ドキュメントはこちら Key-Path Expression 

  2. ドキュメントに記述を見つけられなかったのですが、参照を保持しなかった場合はviewDidLoadを抜けた時点でcancelが呼ばれていました。 

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

tableViewのcellの色を3色で循環させる

はじめに

初投稿です。よろしくお願いします。
tableViewの練習のため、https://www.youtube.com/watch?v=BjigVLkRt8o を参考にサンプルアプリを作っていたところ、躓いた部分があったので、共有したいと思います。
サンプルアプリの詳細はリンク先をご参照ください。

自分の回答

まずリンク先のサンプルアプリを僕なりに作ってみたのでそのコードを貼ります。
cellはxibで作りました。

TableViewCell.swift
import UIKit

final class TableViewCell: UITableViewCell {

    static let reuseIdentifier = "tableViewCell"

    @IBOutlet private weak var stuckView: UIStackView!
    @IBOutlet private weak var prefectureNameLabel: UILabel!
    @IBOutlet private weak var prefectureNumberLabel: UILabel!

    override func prepareForReuse() {
        super.prepareForReuse()
        prefectureNameLabel.text = nil
        prefectureNumberLabel.text = nil
    }

    func configure(name: String, number: String, color: UIColor) {
        prefectureNameLabel.text = name
        prefectureNumberLabel.text = number
        (prefectureNameLabel.backgroundColor ,prefectureNumberLabel.backgroundColor) = (color, color)
    }

    static func loadNib() -> UINib {
        return UINib(nibName: "TableViewCell", bundle: nil)
    }
}
ViewController
import UIKit

class ViewController: UIViewController {

    let prefectures = ["北海道", "青森県", "岩手県", "宮城県", "秋田県","山形県", "福島県", "茨城県", "栃木県", "群馬県","埼玉県", "千葉県", "東京都", "神奈川県","新潟県","富山県", "石川県", "福井県", "山梨県", "長野県","岐阜県", "静岡県", "愛知県", "三重県", "滋賀県","京都府", "大阪府", "兵庫県", "奈良県", "和歌山県","鳥取県", "島根県", "岡山県", "広島県", "山口県","徳島県", "香川県", "愛媛県", "高知県", "福岡県","佐賀県", "長崎県", "熊本県", "大分県", "宮崎県","鹿児島県", "沖縄県"]

    let colors: [UIColor] = [.red, .green, .blue]

    @IBOutlet private weak var tableView: UITableView! {
        didSet {
            tableView.register(TableViewCell.loadNib(), forCellReuseIdentifier: TableViewCell.reuseIdentifier)
        }
    }

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

}

extension ViewController: UITableViewDataSource {

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

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: TableViewCell.reuseIdentifier, for: indexPath) as? TableViewCell else { return UITableViewCell() }
        cell.configure(name: prefectures[indexPath.row], number: "\(indexPath.row + 1)番目の都道府県です", color: colors[indexPath.row])

        return cell
    }
}

つまずいたところ

サンプルと同じように、cellの背景色を赤→緑→青と繰り返したいので、
colors: [UIColor] = [.red, .green, .blue]
と配列を作り、
cell.configure(name: prefectures[indexPath.row], number: "\(indexPath.row + 1)番目の都道府県です", color: colors[indexPath.row]) 
のcolor引数で循環させようと思いましたが、実行しようとするとFatal error: Index out of rangeというエラーが出てアプリが落ちてしまいました。

「cellは47個分できているのに、colors配列に入っている要素は3つだけなので、colors配列の要素だけでは47個のcellをカバーできないよ」という理由で怒られているのだと思います。(間違えてたらすみません)
今回のように3色以上ではなく、cellの背景を2色交互に表示したい時の場合は、if文で
indexPath % 2 == 0の場合分けでできるのは知っていたのですが、3色以上で背景色を繰り返したい場合のやり方がわからず、詰まってしまいました...

解決方法

ViewController
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: TableViewCell.reuseIdentifier, for: indexPath) as? TableViewCell else { return UITableViewCell() }
         let colors: [UIColor] = [.red, .green, .blue]
        cell.configure(name: prefectures[indexPath.row], number: "\(indexPath.row + 1)番目の都道府県です", color: colors[indexPath.row % 3])

        return cell
    }

意外と簡単でした。
color引数の部分をcolors[indexPath % 3]とするだけ。
indexPath % 2 == 0の場合と考え方はほぼ同じで、indexPathを3で割った余りが2の場合は.red、1の場合は.green、0の場合は.blueでcolors配列の中身を振り分ける ということです。
今回は3色でしたが、4色以上のときも同じようにできます。

結果

サンプルと同じようにできました。
Simulator Screen Shot - iPhone SE (2nd generation) - 2020-08-01 at 01.34.05.png

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

Swiftでパズルゲーム制作を開始した

動機

今まで独自のゲームを作ってばかりでしたが、全然売れなかったので、有名ゲームをパク・・参考にすることにしました。
とりあえず形から入ろうということで、ドラゴンとパズルをテーマにすることにしました。

このテーマで有名なゲームを参考にしていたのですが、「面白いか?」と単純な疑問を抱きました。
もう少し分かりやすいルールのパズルの方が良いのではと思い、別の有名ゲームを参考にしました。
ツムツムかポコパンかよく覚えていませんが、その辺りのゲームのルールが分かりやすそうだったので、パズル部分は隣接するアイテムをなぞって消すルールにしました。

現状

TestFlightでベータ版をテストしている状態です。

ゲームロジック

動きの処理は、1つの要素の下の要素と当たり判定をとって、当たってなければ落下する感じです。
消す処理は、同じ色の要素を選択したら消える。同じ番号の要素を選択したら消える。同じ形の要素を選択したら消える。という感じです。

下記は同色の要素がなぞられたかを判断しています。

        var i: Int = -1
        var count1: Int = 0
        for e in elements {
            if e.select {
                if i != -1 {
                    if i == e.colorNumber {
                        e.delete = true
                        e.deleteY = e.shape?.position.y
                        count1 += 1
                    } else {
                        count1 = -1
                        break
                    }
                }
                i = e.colorNumber!
            }
        }

        if count1 >= 1 {
            for e in elements {
                if e.select {
                    if i == e.colorNumber{
                        e.delete = true
                        e.deleteY = e.shape?.position.y
                        break
                    }
                }
            }

            for e in elements {
                if e.delete {
                    initElement(e: e)
                }
            }
        }
        if count1 > 0 {
            addPoint(p: count1)
        }

まとめ

ソースは GitHub にアップしています。

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