- 投稿日:2019-07-07T22:05:47+09:00
【Swift学習まとめ】 スコープ
スコープとは
変数、定数、関数、型の名前の有効範囲を表すもの
適用範囲に応じてグローバルスコープ、ローカルスコープに分類される
全ての変数、定数、関数、型はどちらかのスコープに属する約束事
同じスコープ内には同じ名前を複数存在させることはできない
※変数、定数、関数、型の種類が異なっていても同様ローカルスコープ
関数や制御構文の内部で定義されるスコープ
外部からの参照はできず、関数や制御構文の実行文の内部でのみ有効のため
意図しない変更が起こりにくいメリットがある
グローバルスコープ
関数、型宣言の外部で定義されるスコープ
宣言された変数や定数はファイル外を含めどこからでも参照可能だが、意図しない変更を招きやすいため、ローカルスコープでの宣言よりも説明的な命名が必要である
参考文献
- 投稿日:2019-07-07T18:03:01+09:00
StoryboardでScrollView
contenViewをxibに
1.contenViewをxibにする
2.ViewControllerにはコードでaddsubView&制約追加contentViewをcontainerViewに
参考記事
・StoryboardでUIScrollViewを用いる際、ContainerViewを使うと便利
・Storyboard 上で UIScrollView を AutoLayout を使って設定する
・@1amgeekさんのツイート
- 投稿日:2019-07-07T15:23:18+09:00
ライフサイクル 優良記事
制約の更新のタイミングなどの参考になるかも
・基礎からやりなおしメモ 【ライフサイクルと記述ルール】 - Qiita
・UIViewにおけるレイアウトのライフサイクル - Qiita
・ios – 向きの変更後にUIViewフレームが更新されない - コードログ
- 投稿日:2019-07-07T14:09:37+09:00
【Swift】 RealmSwiftのマイグレーション(データ引き継ぎ有)方法
前置き
ネットの情報を色々見て、公式の記述サンプルも見たんですが、Realmのマイグレーションがうまく行かない。より正確には、schemaVersionを更新して、レコードフォーマットも更新されて、アプリが稼働することは確認できるのに、マイグレーション前のデータが引き継がれない。
とにかく「これでマイグレーションできました」っていうブログ等の書き方を片っ端から試していって、結果、下記の書き方でうまく行ったので備忘録として残します。開発環境
端末:MacBook Pro/MacOS 10.14.5(Mojave)
Xcode:10.2.1
Swift:5実装内容
ソースサンプル
RealmSwift.swiftimport Foundation import RealmSwift class myRoutine: Object { @objc dynamic var column1 = String() @objc dynamic var column2 = String() @objc dynamic var column3 = String() @objc dynamic var column4 = String() @objc dynamic var column5 = String() } func realmMigration() { // Realmマイグレーションバージョン // レコードフォーマットを変更する場合、このバージョンも上げていく。 let migSchemaVersion: UInt64 = 1 // マイグレーション設定 let config = Realm.Configuration( schemaVersion: migSchemaVersion, migrationBlock: { migration, oldSchemaVersion in if (oldSchemaVersion < migSchemaVersion) { }}) Realm.Configuration.defaultConfiguration = config }ライフサイクルの早い段階でマイグレーション処理
realmMigration()を呼び出すViewController.swiftclass ViewController: UIViewController { ... // 自分の場合は、作ってるアプリのライフサイクルで一番早いのが // awakeFromNib()だったのでここに書いています。 override func awakeFromNib() { realmMigration() // realmを使う時のおまじない realm = try! Realm() ... } ... }感想、その他メモ
いろいろ試して、(そもそも何でいろいろな書き方があるのか、という話ですが)なんとかデータ引き継ぎできる書き方が見つかってよかったです。
もっと余裕と知識があれば、ダメだった書き方のダメな理由も調べたいんですが、それはまた別の機会に。
- 投稿日:2019-07-07T09:48:16+09:00
ユーザーページの画像をアップロードする
このページの続きです。
⇨
これが完成形です。事前に
❶画像を拾ってくる。
❷画像をNCMBにアップロード
❸画像をユーザーページに読み込む。
の手順でやっていきたいと思います。まずは部品の接続、TextField,TextViewのDelegate接続、userIdTextFieldに現在ログインしているユーザーの取得を行なっていきます。
import UIKit import NCMB class EditProfileViewController: UIViewController,UITextViewDelegate,UITextFieldDelegate { @IBOutlet weak var userImageView: UIImageView! @IBOutlet weak var userIdTextField:UITextField! @IBOutlet weak var userNameTextField: UITextField! @IBOutlet weak var introductionTextView: UITextView! override func viewDidLoad() { super.viewDidLoad() userIdTextField.delegate = self userNameTextField.delegate = self introductionTextView.delegate = self let userId = NCMBUser.current()?.userName userIdTextField.text = userId } func textFieldShouldReturn(_ textField: UITextField) -> Bool { textField.resignFirstResponder() return true } func textViewShouldEndEditing(_ textView: UITextView) -> Bool { textView.resignFirstResponder() return true } @IBAction func close(_ sender: Any) { self.dismiss(animated: true, completion: nil) } }そしてここからカメラとフォトライブラリーの取得に入っていきます。
またその機能に移る前に、iOS10以降ではプライバシーを扱う前にInfo.plistに書かなければいけないことがあります。
赤色で囲んでいるところを追加し、適当にカメラとフォトライブラリを使うときの文言を書いてください。UIImagePickerController
EditProfileViewController.swift ~~~省略~~~ @IBAction func selectImage(_ sender: Any) { let alertController = UIAlertController(title: "画像の選択", message: "選択してください", preferredStyle:.actionSheet) let cameraAction = UIAlertAction(title: "カメラ", style: .default) { (action) in // カメラ起動 //カメラが使えたら if UIImagePickerController.isSourceTypeAvailable(.camera) == true { let picker = UIImagePickerController() picker.sourceType = .camera picker.allowsEditing = true picker.delegate = self self.present(picker, animated: true, completion: nil) } else { print("この機種ではカメラが使用出来ません。") } } let albumAction = UIAlertAction(title: "フォトライブラリ", style: .default) { (action) in // アルバム起動 if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) == true { let picker = UIImagePickerController() picker.sourceType = .photoLibrary picker.allowsEditing = true picker.delegate = self self.present(picker, animated: true, completion: nil) } else { print("この機種ではフォトライブラリが使用出来ません。") } } let cancelAction = UIAlertAction(title: "キャンセル", style: .cancel) { (action) in alertController.dismiss(animated: true, completion: nil) } alertController.addAction(cameraAction) alertController.addAction(albumAction) alertController.addAction(cancelAction) self.present(alertController, animated: true, completion: nil) }次に選ばれた画像をImageViewに表示するという処理を作っていきます。
とその前に、縦長や横長の画像を表示するために一手間加えます。
UIImageViewを選択した状態で、
ContentModeをAspectFillに、またCliptoBoundsにチェックを入れてください。EditProfileViewController.swift ~~~省略~~~ func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { let selectedImage = info[UIImagePickerController.InfoKey.originalImage] as! UIImage userImageView.image = selectedImage picker.dismiss(animated: true, completion: nil) } ~~~省略~~~これでは画像が保存されません。
そのため拾ってきた画像をNCMBに保存し、アップロードする必要があります。。NCMBに画像をアップロード
その前にiPhoneで取ってきた画像は大きすぎるのでリサイズする必要があります。
そのために今回は簡単なライブラリを紹介します。
NYXImagesKitです。
これをPodfileにpod 'NYXImagesKit'と追加し、pod installを行なってください。
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { let selectedImage = info[UIImagePickerController.InfoKey.originalImage] as! UIImage //NYXImagesKitライブラリでリサイズを行う。 let resizedImage = selectedImage.scale(byFactor: 0.4) picker.dismiss(animated: true, completion: nil) //data型に変換 let data = resizedImage!.pngData() //型を変換 let file = NCMBFile.file(withName: NCMBUser.current()?.objectId,data:data) as! NCMBFile file.saveInBackground({ (error) in if error != nil{ print(error) }else{ self.userImageView.image = selectedImage } }) { (progress) in print(progress) } }次にアップロードした画像を読み込みます。
ユーザーページに読み込む。
ViewController.swift override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. //丸くするコード userImageView.layer.cornerRadius = userImageView.bounds.width / 2.0 userImageView.layer.masksToBounds = true } override func viewWillAppear(_ animated: Bool) { if let user = NCMBUser.current() { let file = NCMBFile.file(withName: (user.objectId)!, data: nil) as! NCMBFile file.getDataInBackground { (data, error) in if error != nil{ print(error) }else{ if let image = UIImage(data: data!){ self.userImageView.image = image } } } }else{ // NCMBUser.current()がnilだったとき let storyboard = UIStoryboard(name: "SignIn", bundle: Bundle.main) let rootViewController = storyboard.instantiateViewController(withIdentifier: "SignInController") UIApplication.shared.keyWindow?.rootViewController = rootViewController // ログイン状態の保持 let ud = UserDefaults.standard ud.set(false, forKey: "isLogin") ud.synchronize() } }また、このような画像をImageViewのImageに設定しておけば、画像が読み込まれる前に表示することができます。
以上で完成です。
- 投稿日:2019-07-07T07:11:10+09:00
【Swift】 UITextFieldに文字数制限を設ける方法
前置き
少し久しぶりのQiita投稿。
(自作アプリ公開に向けて日々いろいろやってたんですが、細かいトコの修正やら稼動確認してると、今までの反復に当たる部分でぶつかる壁が多くて、あまり目新しい収穫がなかったので。)さて表題の件。
ブログ等を参考にしても、エントリ時期から時間が経ってSwiftの書き方にギャップが出たり、(日本語入力もカバーするか、という点で)実装の仕方に違いがあったりで、マネしてみても自分の想定する実装にならないコトが多い。
最終的に、いささか記事のエントリ時期としては古くて、少しSwift5に対応するために修正は必要だったけれど、下記「参考」記載のURLのブログエントリが自分なりに一番取り込みやすい内容でした。開発環境
端末:MacBook Pro/MacOS 10.14.5(Mojave)
Xcode:10.2.1
Swift:5実装内容
「こういうコトやりたい」だけ前置きに書いていても、
実際、下記のソースで何ができるようになったかが伝わりづらいかもしれないので、
どんなコトがどんな風にできるのか、できるだけ書くようにしようかな、と。
(今回は画面イメージもないので)・UITextFieldに対する、入力文字数の制限。
・日本語入力(入力→変換→確定、というプロセス)でもOK。
入力確定時に制限文字数以上であれば切り捨てる。
・あくまで制限文字数のある項目1つに対する入力制限の実装。
(複数の項目で、それぞれ制限文字数が異なるような場合、別途カスタマイズは必要。)
・ソースサンプル
ViewController.swiftclass ViewController: UIViewController, UITextFieldDelegate { // 入力チェックを行うUITextField @IBOutlet weak var myTextField: UITextField! // 入力可能な最大文字数 let maxLength: Int = 5 override func viewDidLoad() { super.viewDidLoad() myTextField.delegate = self // myTextFieldの入力チェック(文字数チェック)をオブザーバ登録 NotificationCenter.default.addObserver(self, selector: #selector(textFieldDidChange(notification:)), name: UITextField.textDidChangeNotification, object: myTextField) } // オブザーバの破棄 deinit { NotificationCenter.default.removeObserver(self) } // 入力チェック(文字数チェック)処理 @objc func textFieldDidChange(notification: NSNotification) { let textField = notification.object as! UITextField if let text = textField.text { if textField.markedTextRange == nil && text.count > maxLength { textField.text = text.prefix(maxLength).description } } } ... }参考
・雑食プログラミング備忘録
[iOS] UITextFieldの最大文字数を設定する
http://chicketen.blog.jp/archives/50002171.html感想
会社での担当業務としてHTMLを触るコトが多いのもあって、UITextFieldの文字数制限くらいStoryboardでチャチャっと設定できると思っていたトコロから、気づいたら実装・稼動確認、そしてここへアウトプットするのも合わせるとフツーに2、3時間経ってました。
英語入力だけの文字数制限だけなら割とすぐにできたトコロから、日本語に対応したモノへ発展させるのにけっこう悩まされました。Swift2,3の頃の記事が多くて、Swift4,5だと書き方が全然違って来てる(もしくは同じ挙動にならない)っていうコトに割と出くわすので、自分自身がSwift5で色々試して、そのギャップを埋めるコトにささやかながら貢献できれば嬉しいです。












