20190816のSwiftに関する記事は6件です。

RxSwift学びの過程〜tableViewCellの操作編〜

背景

既存コードをRxSwiftにて書き直していたとき、cellの操作で詰まりましたので備忘録的にアウトプット。
やはりこいつはすごくクセが強い。

cell上に配置したUIButtonの操作

Issue 1 : cell番号を取得したかった

MVVMで開発をしていてcellCustomCellとして作成していたとき、UIButtonをセル上に配置していたのでボタンタップの検知をCustomCellViewに記載していました。
ちなみにUIButtonのタップ検知は

  • UIButton.rx.tap

となります。

ここで、UIButtonをタップした時にそのcellのindex(tag)を取得したかったのですが、どのセルのボタンをタップしても0しか取得できませんでした。

func favButtonSetup() {
    favButton.rx.tap.asDriver().drive(onNext: { [weak self] _ in

        let row = self!.tag
        print(row) // 選択されたセルのインデックス(tag)を取得したかったが、いつも0

    }).disposed(by: disposeBag)
}

RxSwiftを使わないプレーンな書き方だと@IBOutlet buttonTapped(_:)にてself.tagで任意のセルに乗っかっているボタンのイベントを取得できるんですよね。

Issue2 : お気に入りボタンのon/off切り替えが上手くいかない

お気に入りボタンのon/off、データの整合などで操作対象のcellを取得したいときにもtagで操作対象の番号を取得するやり方は使えます。

セルの位置に応じてお気に入りボタンをon/off処理(画像を切り替える)ものも実装していましたが、取得できる番号が0のみなのでどのボタンを押しても切り替わるのは一番上のセルだけでした。

コードは大したことないのを上に追加するだけなので割愛します。

原因・解決法

まず調べた中での解決法として、

  • tap.asDriver()ViewControllerにあるセルをどうこうする場所で呼ぶ。(cellForRowAtとかRxTableViewSectionedReloadDataSourceとか人によって違うと思います)
  • override func prepareForReuse()にてDisposeBag()を毎度作成し、これでDisposeする
// ViewController内
dataSource = RxTableViewSectionedReloadDataSource<SectionModel>(configureCell: {(_, tableView, indexPath, item) in
    let cell = tableView.dequeueReusableCell(withIdentifier: "ListCell") as! ListCell

    cell.configure(item: item)

    cell.favButton.rx.tap.asDriver().drive(onNext: { [weak self] _ in

        //TableViewCell内での記述ではないので indexPath にて rowを取得
        let row = indexPath.row

    //cell側で作成したdisposeBag()を呼ぶ
    }).disposed(by: cell.disposeBag)

    return cell
})



// CustomCellView内
var disposeBag = DisposeBag()

override func prepareForReuse() {
    disposeBag = DisposeBag()
}

これにはTableViewCellというオブジェクトを作成するライフサイクルに元付いた問題があり、毎度セルを作成する際に作るDisposeBag()Disposeする必要があるようです。

終わりに

問題は解決されました。
が、設計上CellViewにある操作はCustomCellViewで行った方がいいんだろうなぁと思うので、このようにViewControllerにcellの操作を書くのはナンセンス?と思います。

CellView内でUIButton時にcellの番号が取得できたりする方法があれば教えていただければ嬉しいです。

参考URL
How to use rx_tap on UIButton of UITableViewCell · Issue #288 · ReactiveX/RxSwift · GitHub
what is best way i can handle button tap in UITableViewCell using RX. · Issue #119 · RxSwiftCommunity/RxDataSources · GitHub
RxSwift UITableViewCell上に配置したボタンの動作 - Qiita

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

[Swift]ストーリーボートでオブジェクトが重なってしまって編集できない時の解決方法

swiftのストーリーボートを使用している時にオブジェクトが重なってしまって下に紛れ込んだLabelが編集できないことが起きたことはないだろうか。

この解決方法を今回は説明する。

ドキュメントアウトラインを表示

スクリーンショット 2019-08-16 22.37.24.png
ドキュメントアウトラインとはオブジェクトの詳細が一覧で確認できるもので、
今回はLabelとImageViewがオブジェクトとして入っている。

この画像を見たらImageViewの下にLabelが紛れ込んでいる。
このLabelを編集するためには、ドキュメントアウトラインの見方を解説しなければならない。

ドキュメントアウトラインの見方

スクリーンショット 2019-08-16 22.46.31.png

解決

Labelと双眼鏡.jpgを入れ替えLabelを一番上に配置するとLabelが編集できた。

image.png

まとめ

Swiftは、これどうやるの?って思って調べても英語の文献しか出てこない場合が多いので、こういった基礎的な所で詰まってしまいがちだが一個一個覚えて行くしか上達の道はないので地道に頑張る。この記事がいろんな人の助けになればと思います!

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

オプショナル、nil関連まとめ[Swift]

あとで追記

guard

guard letとif letの使い分け - Qiita
Swift の guard は正しく使いましょう - Qiita
Swift 2.0 で追加された guard のいいところ - Qiita

まとめ

guard letは値がnilかどうかのチェック・アンラップを同時に行える
guard let {}nilならスコープ内で処理を止められる

型?

エラー文

before.swift
.map { [weak self] huga -> String in
           guard let hoge = huga else { return nil } //ここなんでnilつけるん
           //省略
           return hogehogeString
     }
'nil' is incompatible with return type 'String'

Stringだとnilは存在できません(許容できません)

after.swift
.map { [weak self] huga -> String? in
           guard let hoge = huga else { return nil } //ここなんでnilつけるん
           //省略
           return hogehogeString
     }

nilが入っても大丈夫なString?にすることでエラー解消

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

iOS13でアプリがクラッシュするようになった話

環境

  • iPhone8
  • iOS13 β3 and β6

原因

  • layoutIfNeededを呼び出しているコードがメインスレッドではなかった

備考

  • iOS10~12の範囲内では動作に支障がなかった
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AppStoreからギャンブルアプリ認定され、アプリの配信ができなくなった

製作したアプリについて

私が今回製作したアプリは匿名で不特定多数の人とチャットができるiconChatというものでした。githubのリンクはこちら

私は初めてのアプリ製作だったため、何度かApp Store Reviewに審査を出しては修正の繰り返しをしていたのですが、7回目のリジェクトで以下のような内容が届きました。

App Store Reviewからのリジェクトメール(原文)

Guideline 1.2 - Safety - User Generated Content

Your app enables users to post content anonymously but does not have the proper precautions in place.

Next Steps

To resolve this issue, please revise your app to implement all of the following precautions:

  • Age rating must reflect 17+
  • Require that users agree to terms (EULA) and these terms must make it clear that there is no tolerance for objectionable content or abusive users
  • A method for filtering objectionable content
  • A mechanism for users to flag objectionable content
  • A mechanism for users to block abusive users
  • A mechanism for users to immediately remove posts from the feed
  • Developer must act on objectionable content reports within 24 hours by removing the content and ejecting the user who provided the offending content
  • Developer must provide contact information in the app itself, giving users the ability to report inappropriate activity

Dear Developer,

In order to reduce fraudulent activity on the App Store and comply with government requests to address illegal online gambling activity, we are no longer allowing gambling apps submitted by individual developers. This includes both real money gambling apps as well as apps that simulate a gambling experience.

We found that you have submitted this app under an individual account and indicated in the Ratings section of App Store Connect that it contains simulated gambling. As a result, this app has been removed from the App Store. While you can no longer distribute gambling apps from this account, you may continue to submit and distribute other types of apps to the App Store.

If your app does not include gambling content, it would be appropriate to revise your app's rating in App Store Connect to more accurately reflect the content available in your app. Once you have updated your app's rating in App Store Connect, you can submit your app for review.

Going forward only verified accounts from incorporated business entities may submit gambling apps for distribution on the App Store. Visit the Enrollment page to learn more about enrolling an organization in the Apple Developer Program. For information on transferring an app to another developer account, please review the App transfer overview page in App Store Connect Developer Help.

As a reminder, the App Store Review Guidelines state that it is your responsibility to ensure your app complies with all legal requirements in any location where you make it available. Submitting apps designed to mislead or harm customers or evade the review process may result in the termination of your Apple Developer Program account. Review the Terms & Conditions of the Apple Developer Program to learn more about our policies regarding termination.

Best regards,

App Store Review

メール内容の翻訳

ガイドライン1.2-安全性-ユーザー生成コンテンツ

このアプリを使用すると、ユーザーはコンテンツを匿名で投稿できますが、適切な予防措置はありません。

次のステップ

この問題を解決するには、アプリを修正して次のすべての予防措置を実装してください。

-年齢の評価は17歳以上を反映している必要があります
-ユーザーが条件(EULA)に同意することを要求します。これらの条件は、不快なコンテンツや虐待的なユーザーに寛容でないことを明確にする必要があります
-不快なコンテンツをフィルタリングする方法
-ユーザーが不快なコンテンツにフラグを立てるメカニズム
-不正ユーザーをブロックするためのメカニズム
-フィードから投稿をすぐに削除するためのメカニズム
-デベロッパーは24時間以内に不快なコンテンツレポートに基づいてコンテンツを削除し、問題のあるコンテンツを提供したユーザーを退出させる必要があります
-デベロッパーはアプリ自体で連絡先情報を提供する必要があり、ユーザーが不適切なアクティビティを報告できるようにします

親愛なる開発者、

App Storeでの不正行為を減らし、違法なオンラインギャンブル活動に対処する政府の要求に準拠するため、個々のデベロッパーが提出したギャンブルアプリを許可しなくなりました。これには、リアルマネーギャンブルアプリとギャンブル体験をシミュレートするアプリの両方が含まれます。

このアプリを個別のアカウントで送信し、App Store Connectの評価セクションにギャンブルのシミュレーションが含まれていることを示していることがわかりました。その結果、このアプリはApp Storeから削除されました。このアカウントからギャンブルアプリを配布することはできなくなりましたが、引き続き他の種類のアプリをApp Storeに送信および配布することができます。

アプリにギャンブルコンテンツが含まれていない場合は、App Store Connectでアプリの評価を修正して、アプリで利用可能なコンテンツをより正確に反映することが適切です。 App Store Connectでアプリの評価を更新したら、レビューのためにアプリを送信できます。

今後、法人事業体からの確認済みアカウントのみが、App Storeでの配布のためにギャンブルアプリを送信する場合があります。 Apple Developer Programへの組織の登録の詳細については、登録ページをご覧ください。アプリを別のデベロッパーアカウントに移行する方法については、App Store Connectデベロッパーヘルプのアプリ移行の概要ページをご覧ください。

念のため、App Storeレビューガイドラインでは、アプリが利用可能な場所のすべての法的要件にアプリが準拠していることを確認するのはユーザーの責任であると述べています。顧客を誤解させたり、危害を加えたり、審査プロセスを回避するように設計されたアプリを提出すると、Apple Developer Programアカウントが終了する場合があります。 Apple Developer Programの利用規約を確認して、終了に関するポリシーの詳細をご覧ください。

宜しくお願いします、

App Storeレビュー

結論

個人で登録したApple Developer Programのアカウントではギャンブル性のあるアプリは申請できないようです。私のアプリはギャンブル体験をシミュレートするアプリとして認定されてしまったので、このアプリをどうしても公開したいとなると、法人としてApple Developer Programに登録したアカウントをつくり、アプリをそのアカウントに移行してApp Storeに申請する必要があるようです。また、今回のように法的要件にアプリが準拠していることを確認するのはユーザーの責任になるため、最悪の場合はApple Developer Programアカウントが終了することもあるようです。

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

FizzBuzz問題をSwiftで書いてみる

Swift4.0想定です。

問題

1から100までの数をプリントするプログラムを書け。
ただし3の倍数のときは数の代わりに「Fizz」と、5の倍数のときは「Buzz」とプリントし、
3と5両方の倍数の場合には「FizzBuzz」とプリントすること。
http://www.aoky.net/articles/jeff_atwood/why_cant_programmers_program.htm

当然できるよな?

ちゃんとしたプログラマであれば、これを実行するプログラムを2分とかからずに紙に書き出せるはずだ。
怖い事実を聞きたい?

コンピュータサイエンス学科卒業生の過半数にはそれができないのだ。
自称上級プログラマが答えを書くのに10-15分もかかっているのを見たこともある
http://www.aoky.net/articles/jeff_atwood/why_cant_programmers_program.htm

解いてみた

僕も10分くらいかかりました。

FizzBuzz
for i in 1...100 {
    if i % 3 == 0 && i % 5 == 0 {
        print("FizzBuzz")
    } else if i % 3 == 0 {
        print("Fizz")
    } else if i % 5 == 0 {
        print("Buzz")
    } else {
        print(i)
    }
}
出力
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
17
Fizz
19
Buzz
Fizz
22
23
Fizz
Buzz
26
Fizz
28
29
FizzBuzz
31
32
Fizz
34
Buzz
Fizz
37
38
Fizz
Buzz
41
Fizz
43
44
FizzBuzz
46
47
Fizz
49
Buzz
Fizz
52
53
Fizz
Buzz
56
Fizz
58
59
FizzBuzz
61
62
Fizz
64
Buzz
Fizz
67
68
Fizz
Buzz
71
Fizz
73
74
FizzBuzz
76
77
Fizz
79
Buzz
Fizz
82
83
Fizz
Buzz
86
Fizz
88
89
FizzBuzz
91
92
Fizz
94
Buzz
Fizz
97
98
Fizz
Buzz

最初独立したif文を3つ作り、Fizz判定、Buzz判定、両方でない判定で出力する方針で組んだんですが、
Swiftのpritnの仕様上、改行文字を入れちゃうので、「FizzBuzz」とはならずに、
「Fizz
Buzz」になってしまいました。

print("改行しない", terminator: "")

こっちを使うと改行しないので、if文の中ではこれを使い、最後に
print("\n")で一律改行させることで回避しようとしたら、これはこれできれいな出力にならなかったので、
直感的なわかりやすさを落として、最初にFizzBuzz判定を入れました。
デバッグしながら10〜15分でしたが、紙とペンだと厳しいかもですね。

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