アプリ開発メモ
セルの色を交互に変えるのと、セパレーターの削除
if (indexPath.row == 0 || indexPath.row%2 == 0) {
cell.backgroundColor = UIColor(hex: "FFFFFF")
}
tableView.tableFooterView = UIView(frame: .zero)
- IQKeyboardManager
これを入れずに作ってから、入力がめっちゃ不便なことに気がついた...
絶対忘れずに入れないとと心に誓った
NoSQL(NotOnlySQL)
- ビッグデータに対応すべく生み出された技術
- 大量のデータを扱うサービスで参照や追加処理が主な処理である場合に高速
- データの整合性よりも大量のデータを素早く処理することを優先
- joinリクエストができない
- データを重複して持つことを許容する
- トランザクションは存在しない
RDBとNoSQLの違いで戸惑っているためメモ
- 返り値がVoidのClosureでAが終わったらBを実行
結構前に詰まったのでメモ
IBDesignablesエラー
- 以下をPodfileに追加
- pod update
post_install do |installer|
installer.pods_project.build_configurations.each do |config|
config.build_settings.delete('CODE_SIGNING_ALLOWED')
config.build_settings.delete('CODE_SIGNING_REQUIRED')
end
end
また今日も「え?え?」となってしまったから書いておく
TextFieldが空かどうかはnilじゃなくて""で判定する
textField.text != ""
- Firestorageに保存した画像を表示する
FirestoreにimageNameとして名前を保存していたのでそれと照らし合わせたい
static func setImage(image: String, imageView: UIImageView){
let storageRef = Storage.storage().reference()
let ref = storageRef.child(image)
imageView.sd_setImage(with: ref)
}
とすると、下記のエラー
Value of type 'UIImageView' has no member 'sd_setImage'
この2つをCocoaPodsでインストールしなきゃいけなかったらしい
- FirebaseUI
- SDWebImage
NavigationControllerで2画面前に戻りたくて下記を参考に実装
StoryBoardでUIButtonのタイトルをAttributedにするとsetTitleが効かず、タイトルの変更ができないのでコードで設定する
アイコンの作成
- 1024×1024の画像を作成する
- https://appicon.co/ でアイコンファイルを作成する
- XcodeのAssets.xcassets→AppIconを選択
- Delete Selected ItemsでAppIconを削除
- ファイルの中のAppIcon.appiconsetフォルダを選択→Assets.xcassetsにフォルダごとドラッグ&ドロップ
IPAファイルの作成とインストール In House配布用(Enterprise)
- XcodeのProduct→Archiveでアーカイブ作成
- OrganizerからEnterpriseを選択、証明書とProvisioningFileを設定して作成
- Apple Configuratorを開く
- 接続したスマホが表示されたらHome画面に.ipaファイルをドロップ
※AdHocでの配布との違い
- インストール先の端末に制限がない
- Provisioning Profileに登録されていない端末にもインストールできる
Apple Sign-inとGoogle Sign-inをStoryboardで設定する方法
アプリ内に画像を保存/読み取り
func saveImage(imageName: String, imageView: UIImageView) {
// ドキュメントディレクトリのファイルURL
var documentDirectoryFileURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let path = documentDirectoryFileURL.appendingPathComponent(imageName)
documentDirectoryFileURL = path
let jpegImageData = imageView.image!.jpegData(compressionQuality: 1)
do {
try jpegImageData!.write(to: documentDirectoryFileURL)
print("saveimage success")
} catch {
print("saveimage error")
}
}
func loadImage(imageName: String, imageView: UIImageView) {
// ドキュメントディレクトリのパス
let filePath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let fileURL = URL(fileURLWithPath: filePath).appendingPathComponent(imageName)
if let image = UIImage(contentsOfFile: fileURL.path) {
let image = UIImageView(image: image)
imageView.image = image.image
imageView.contentMode = UIView.ContentMode.scaleAspectFill
print("load success")
} else {
print("load error")
}
}
Swift6のasync, await
- 同期の書き方で非同期処理ができる
- 今まではコールバックでやっていたが、ネストが深くなるとわかりにくい
- asyncがついている関数とそうでないものだと型が違うという認識になる
- Kotlinのsuspendに近い
Swift zoominで少しメモをとっていたので見返す用にメモ
ログイン判定(Firebase)
- AuthProtocolを作成
protocol AuthProtocol {
var isLogined: Bool { get }
}
extension AuthProtocol {
var isLogined: Bool { Auth.auth().currentUser != nil }
}
- プロトコルなのでクラスに適用させることができる
class ViewController: UIViewController, AuthProtocol {
override func viewDidLoad() {
super.viewDidLoad()
if isLogind {
// ログインしている時の処理
} else {
// ログインしていない場合の処理
}
}
}
Firebaseの匿名認証の仕組み
- mobileは端末のlocal_storageにtokenを保持
- Android
- SharedPreferences
- 再インストール時に削除
- iOS
- Keychain
- Android
iOSのFirebase SDKの匿名ログイン
アプリを削除して再インストールしても、端末リセットしてiCloudバックアップからリストアした場合でも、同じuidが維持される
Firestoreのデータ保存
- Dateで保存してもTimestampで返ってくる
let timestamp = Dic["date"] as! Timestamp
date = timestamp.dateValue()
TimestampでキャストしてからDateに変換する
アプリの縦横固定
- Device OrientationをPortraitのみチェックする
DarkMode対応(非推奨らしい?)
- info.plistのAppearanceにLightを設定
カレンダーBeforeAfter(少しシンプルになった)
- イベントの丸ポチは文字に変更
- SelectionColorを消す
- 今日の日付に濃いめのピンクでBorder
iOS 証明書 & Provisioning Profileの作成
- ジェネレーターを使用してプライバシーポリシー作成
https://app-privacy-policy-generator.firebaseapp.com/ - 参考
https://qiita.com/Hiroki_Kawakami/items/94f012d20afdb692df20 - Notionに貼り付けて公開
Lottieでアニメーション
- Lottieからjsonファイルをダウンロードする
- Xcodeにファイルを置く
Lottieをインポート
import Lottie
StoryBoardでViewを追加
- ClassをAnimationViewに
- ModuleをLottieとする
あとはこれだけでアニメーションがループで再生される
class ViewController: UIViewController {
@IBOutlet weak var animationView: AnimationView!
override func viewDidLoad() {
super.viewDidLoad()
let customAnimationView = AnimationView(name: "AnimationName")
customAnimationView.frame = CGRect(x: 0, y: 0, width: 150, height: 150)
// ループで再生
customAnimationView.loopMode = .loop
// 一時停止状態で止まり、アプリがフォアグラウンドになるとそこから再生
customAnimationView.backgroundBehavior = .pauseAndRestore
customAnimationView.play()
animationView.addSubview(customAnimationView)
}
}
■animationView.loopMode(Default:.playOnce)一度だけ実行される
アプリがバックグラウンド→フォアグラウンドに切り替わるのを監視する
viewDidLoad内
NotificationCenter.default.addObserver(
self,
selector: #selector(ViewController.viewWillEnterForeground(_:)),
name: UIApplication.willEnterForegroundNotification,
object: nil)
フォアグラウンドになった時の処理を書く
@objc func viewWillEnterForeground(_ notification: Notification?) {
if (self.isViewLoaded && (self.view.window != nil)) {
hoge()
}
}
FirestoreでCollectionを削除する場合はCloudFunctionを使うしかなさそう
なかなか大変そうだったのでDocumentを一旦取得して全削除することにした
func deleteData() {
let ref = Firestore.firestore().collection("hoge")
ref.getDocuments { (snaps, error) in
if let error = error {
fatalError("\(error)")
}
guard let snaps = snaps else { return }
for document in snaps.documents {
let doc = document.documentID
ref.document(doc).delete() { error in
if let error = error {
print("削除失敗: " + error.localizedDescription)
} else {
print("削除成功")
}
}
}
}
}
アプリ公開後のバージョンをアップデートして申請する
- バグ修正、機能追加後にバージョンを変更する
- バージョン管理の目安
0.01単位 軽微な修正、バグ修正
0.1単位 新規機能追加など
1単位 大幅なアップデート - 再申請時にバージョン情報からコメントを追加
- 申請する
TextFieldで名前を入力時に自動でふりがなを表示させる(かな入力用のTextField)
- 下記の記事を参考に追加する
- Delegateメソッドを追加する
(.hiraganaを.katakanaにするとカタカナ表示になる)
func textFieldDidEndEditing(_ textField: UITextField) {
if textField == nameTextfield {
guard let text = nameTextfield.text else { return }
kanaTextfield.text = TextConverter.convert(text, to: .hiragana)
}
}