Open29

アプリ開発メモ

セルの色を交互に変えるのと、セパレーターの削除

if (indexPath.row == 0 || indexPath.row%2 == 0) {
    cell.backgroundColor = UIColor(hex: "FFFFFF") 
 }
tableView.tableFooterView = UIView(frame: .zero)
  • IQKeyboardManager
    これを入れずに作ってから、入力がめっちゃ不便なことに気がついた...
    絶対忘れずに入れないとと心に誓った

NoSQL(NotOnlySQL)

  • ビッグデータに対応すべく生み出された技術
  • 大量のデータを扱うサービスで参照や追加処理が主な処理である場合に高速
  • データの整合性よりも大量のデータを素早く処理することを優先
  • joinリクエストができない
  • データを重複して持つことを許容する
  • トランザクションは存在しない

https://qiita.com/Yu-kiFujiwara/items/c1c52495fd321373c544

RDBとNoSQLの違いで戸惑っているためメモ

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

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に登録されていない端末にもインストールできる

アプリ内に画像を保存/読み取り

  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に近い

https://speakerdeck.com/koher/await

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 {
        // ログインしていない場合の処理
        }
    }
}

JSONからSwiftの構造体を作成する

  • JSON形式のデータを貼り付けると自動的にコードを生成してくれる

https://app.quicktype.io/

Firebaseの匿名認証の仕組み

  • mobileは端末のlocal_storageにtokenを保持
    • Android
      • SharedPreferences
      • 再インストール時に削除
    • iOS
      • Keychain

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

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)
    }
}

https://qiita.com/sgr-ksmt/items/cc8882aa80a59e5a8355
作成者以外のコメントは許可されていません