- ์นดํ ๊ณ ๋ฆฌ ๋ณ๋ก ๋ฉ๋ชจ๋ฅผ ์ ์ฅ
- ๋ฉ๋ชจ ์์ฑ, ํ์ธ, ์์ , ์ญ์ ๊ฐ๋ฅ
- ์ค๋ ๋ฉ๋ชจ๋ Today ํญ์์ ํ์ธ
- ๋คํฌ๋ชจ๋ ๋์
- UIKit
- UI - Storyboard
- CoreData
- MVC โ MVVM ๋ฆฌํฉํ ๋ง
๋ฐ๋ณต๋๋ ์ฝ์ด๋ฐ์ดํฐ ์ ๊ทผ์ผ๋ก ์ฑ์ ๋ฒ๋ฒ ์ ๋ฐ์ ๋ฌธ์ (๋ฉ๋ชจ๋ฆฌ ์บ์ ํ์ฉ์ ํตํด (๋ฐ๋ณต์ ์ธ ์ฝ์ด๋ฐ์ดํฐ ์ฌ์ฉ ๋น๋๋ฅผ ์ค์ฌ) ์ฑ์ ๋ฒ๋ฒ ์ ์ค์ด๊ธฐ)
๐ก ๋ฌธ์ ์ํฉ: ์ฑ์ UI๋ฅผ ๊ทธ๋ฆด ๋๋ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ง๊ณ ์ฌ ๋๋ง๋ค, ๋ฐ๋ณต์ ์ผ๋ก ์ฝ์ด๋ฐ์ดํฐ๋ฅผ ํตํด ๋์คํฌ์ ์ ์ฅ๋ ๋ฉ๋ชจ๋ฅผ ๋ถ๋ฌ์ด โ (๋์คํฌ์ ์์ฃผ ์ ๊ทผํจ์ผ๋ก์จ ๋ฐ์ํ๋) ์ฑ์ ๋ฒ๋ฒ ์์ ์ค์ด๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผ ํ ๊น? (์ฝ์ด๋ฐ์ดํฐ์ ์ปค์คํ ๋ฐ์ดํฐ ํ์ ๋ฑ ์ถ๊ฐ์ ์ธ ๋ฐ์ดํฐ ์ ์ฅ์ผ๋ก ์ธํ ๋ฒ๋ฒ ์ ๋ฌธ์ ํด๊ฒฐ)
-
์ ์ฒด ๋ฉ๋ชจ๋ฅผ ์ฝ์ด์ค๊ณ ๋๋ ๋ฉ๋ชจ๋ฅผ ์์ฑ / ์์ / ์ญ์ ํ ๋๋ง๋ค ์ฝ์ด ๋ฐ์ดํฐ์ ์ ๊ทผํ๊ธฐ ๋ณด๋ค๋,
-
DataManager
๋ด์ (๋ฉ๋ชจ๋ฆฌ ๋ด์์ ๋จผ์ ์ ๊ทผํ๊ณ ์ฌ์ฉํ ์ ์๋) ๋ฉ๋ชจ๋ฆฌ ์บ์(memoList
๋ฐฐ์ด)๋ฅผ ๋ง๋ค์ด- CRUD๋ฅผ ๋ฉ๋ชจ๋ฆฌ ์บ์(๋ฐ์ดํฐ ๊ด๋ฆฌ ๋ฐฐ์ด) ๋ด์์ ์ฒ๋ฆฌํ๊ณ
- UI๋ฅผ ๊ทธ๋ฆฌ๊ฑฐ๋ ๋จ์ํ๊ฒ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ง๊ณ ์ฌ ๋๋ ๋์คํฌ์ ์ ๊ทผํ๋ ๋์ ๋ฉ๋ชจ๋ฆฌ ์บ์(๋ฐฐ์ด)์ ์ ๊ทผํ์ฌ ์ฑ์ ๋ฒ๋ฒ ์์ ์ค์
(์์) ์ฝ์ด๋ฐ์ดํฐ ์ง์ ์ ๊ทผ โ ๋ฉ๋ชจ๋ฆฌ ์บ์(๋ฐฐ์ด)์ ์ ๊ทผ
์์ ์ -> memoDataManager.getMemoListFromCoreData().count (์ฝ์ด๋ฐ์ดํฐ ์ ๊ทผ) ์์ ํ -> memoDataManager.memoList.count ๋ก ๋ณ๊ฒฝ (๋ฉ๋ชจ๋ฆฌ ์บ์ ์ ๊ทผ)
(์์) ๋ฐ์ดํฐ ์ญ์ ์, ์ฝ์ด๋ฐ์ดํฐ ์ง์ ์ ๊ทผ โ ๋ฐฐ์ด(๋ฉ๋ชจ๋ฆฌ ์บ์)์ ๋จผ์ ์ฒ๋ฆฌ ํ, ์ฝ์ด๋ฐ์ดํฐ์ ํ ์ฒ๋ฆฌ
์์ ์ ) func deleteMemo(_ memo: MemoData?, at index: Int) { //..... mainContext.delete(deletingMemo) // ์ฝ์ด๋ฐ์ดํฐ์ ์ง์ ์ ๊ทผ ์ญ์ saveContext() } ์์ ํ) func deleteMemo(_ memo: MemoData?, at index: Int) { //..... memoList.remove(at: index) // ๋ฉ๋ชจ๋ฆฌ ์บ์ ๋ด์์ ์ญ์ ํ mainContext.delete(deletingMemo) // ์ฝ์ด๋ฐ์ดํฐ์ ์ง์ ์ ๊ทผ ์ญ์ saveContext() }
๊ธฐ๋ณธ MVC์์ ๋ฐ์ดํฐ ๊ด๋ฆฌ ๊ณ์ธต(Layer)์ ๋ถ๋ฆฌ์ MVVM์ผ๋ก ์ถ๊ฐ์ ์ธ ๋ฆฌํฉํ ๋ง (๊ฐ์ฒด์งํฅ ๊ด์ , ํฅํ ์ ์ง๋ณด์๋ฅผ ๊ณ ๋ คํ ์ค๊ณ)
๐ก ๋ฌธ์ ์ํฉ: ๊ธฐ๋ณธ MVC ์ํคํ ์ฒ ๊ตฌ์กฐ์์, ๊ฐ ๋ทฐ์ปจํธ๋กค๋ฌ๊ฐ ์ฝ์ด๋ฐ์ดํฐ์ ์ง์ ์ปค๋ฎค๋์ผ์ด์ ์ ํ๊ณ , ์๋ง์ ๋ก์ง์ ๋ณด์ ํจ์ผ๋ก ๋น๋ํด์ง ๋ทฐ์ปจํธ๋กค๋ฌ๊ฐ ๋์์. ๋ํ ๋นํจ์จ์ ์ธ ๋ฐ์ดํฐ ๊ด๋ฆฌ๊ฐ ์ด๋ฃจ์ด์ง.
- MVC ๊ธฐ์กด๊ตฌ์กฐ - ๊ฐ ๋ทฐ์ปจํธ๋กค๋ฌ์์ ์ฝ์ด๋ฐ์ดํฐ์ ์ง์ ์ ๊ทผํ๋ CRUD ๋ก์ง๋ณด์ ๋ก ์ธํ ๋ฐ์ดํฐ ๊ด๋ฆฌ ์ด๋ ค์๊ณผ ๋น๋ํด์ง ๋ทฐ์ปจํธ๋กค๋ฌ
- ์ฝ์ด๋ฐ์ดํฐ์ ์ปค๋ฎค๋์ผ์ด์ ํ๋ ๋ฐ์ดํฐ ๊ด๋ฆฌ ๊ฐ์ฒด๋ฅผ ์ค๊ฐ์ ์ถ๊ฐํด์, ๋ก์ง์ ๋ถ๋ฆฌํ๊ณ ํจ์จ์ ์ธ ๋ฐ์ดํฐ๋ฅผ ๊ด๋ฆฌํ๋๋ก ๊ตฌ์กฐ๋ฅผ ๋ณ๊ฒฝ
- ๋ฐ์ดํฐ ๋ถ๋ถ ๋ก์ง์ ๋ฐ๋ก ๋ถ๋ฆฌํด์ ๋ฐ์ดํฐ ๊ด๋ฆฌ ๊ฐ์ฒด์ ์ญํ ์ ๋ถ๋ฆฌ์์ผ ๋ณด๋ค ๋จ์ํ ๋ทฐ์ปจํธ๋กค๋ฌ์ ๊ตฌ์กฐ๋ฅผ ์ ์ง์์ผฐ์
๊ธฐ์กด์ MVCํ๋ก์ ํธ๋ฅผ MVVM์ผ๋ก ๋ฆฌํฉํ ๋ง (ํฅํ ์ ์ง๋ณด์ ๋ฐ ํ ์คํธ๋ฅผ ๊ณ ๋ คํ ์ค๊ณ๋ก ๋ฆฌํฉํ ๋ง)
๐ก ๋ฌธ์ ์ํฉ: ์ฌ์ ํ ๋น๋ํ ๋ทฐ์ปจํธ๋กค๋ฌ์์, ํฅํ ์ ์ง๋ณด์๋ฅผ ๊ณ ๋ คํด ๋ณด๋ค ํจ์จ์ ์ธ ํ๋ก์ ํธ ๊ตฌ์กฐ๋ฅผ ๊ณ ๋ฏผ
- MVVM ์ํคํ ์ฒ - ์ฌ์ ํ ๋ง์ ๋ก์ง์ด ๋ทฐ์ปจํธ๋กค๋ฌ์์ ์ด๋ฃจ์ด์ง๊ณ ์๋ค๋ ์ ์์ ๋ฒ์ด๋ ๋ทฐ๋ชจ๋ธ(ViewModel)์ ๋์ ํ์ฌ ๋ก์ง์ ๋ํ ์์ ํ ๋ถ๋ฆฌ๋ฅผ ๊ฒฐ์
- MVC์์๋ ์ฌ์ค์ View์ Controller๊ฐ ํฉ์ณ์, ๋น๋ํ Controller(๋ทฐ์ปจํธ๋กค๋ฌ)๋ฅผ ์ ์งํ์์ง๋ง ๋ทฐ๋ชจ๋ธ์ ์ค๊ฐ ๊ณ์ธต์ ์ฝ์ ํ์ฌ ๋ก์ง์ ๋ถ๋ฆฌ
- ๋น๋ํ ๋ทฐ์ปจํธ๋กค๋ฌ์์ ์ด์ ๋ ๋ณด๋ค ์ฌํํ ๋ทฐ(๋ทฐ์ปจํธ๋กค๋ฌ)๋ฅผ ์ ์งํ ์ ์์๊ณ , ๋ก์ง์ ๋ทฐ๋ชจ๋ธ์์ ๊ด๋ฆฌํด์ ํฅํ ์ ์ง๋ณด์ ๊ด์ ์์ ๋ณด๋ค ํจ์จ์ ์ธ ํ๋ก์ ํธ ๊ด๋ฆฌ๊ฐ ๊ฐ๋ฅํด์ก์
CoreData์์ ๊ธฐ๋ณธ์ผ๋ก ์ง์ํ์ง ์๋ ์ปค์คํ ํ์ ์ ์ฅํ๊ธฐ (์ปค์คํ ๋ฐ์ดํฐ ํ์ ๊ณผ CoreData ํ์ฉ ๋ฌธ์ )
๐ก ๋ฌธ์ ์ํฉ: ์ฝ์ด๋ฐ์ดํฐ ๋ด์ ์ํฐํฐ์ ์์ฑ์ ์ค์ํํธ์ Basic(๊ธฐ๋ณธ) ํ์ ์ ์ง์ ํ ์ ์๋๋ฐ, ์ปค์คํ ํ์ ์ ์ํฐํฐ์ ์์ฑ์ผ๋ก ์ฌ์ฉํ๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผํ ๊น?
- ์ฝ์ด๋ฐ์ดํฐ์์ ์ง์ํ์ง ์๋ ํ์
์ ์ ์ฅํ๊ธฐ ์ํด์๋
Transformable
ํ์ ์ ์ฌ์ฉํด์ผ ํ๊ณ , 3๊ฐ์ง ์๊ตฌ์ฌํญ์ ์ ์ฉํด์ผ ํจ-
์ ์ฅํ๋ ค๋ ๋ฐ์ดํฐ๊ฐ NSSecureCoding ํ๋กํ ์ฝ ์ค์ํด์ผ๋ง ํจ
- NSSecureCoding ํ๋กํ ์ฝ ์ฑํ
- ํด๋น ์๋ฃํ์ด NSSecureCoding ํ๋กํ ์ฝ์ ๋ฐ๋ฅด์ง ์๊ธฐ ๋๋ฌธ์ NSString์ผ๋ก ๋ณํํ๊ณ ์ธ์ฝ๋ฉ
- Core Data์์ ๋ฐ์ดํฐ๋ฅผ ๊ฒ์ ํ ๋ decodeObject(of: forKey :)๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ์ฒด๋ฅผ ๋์ฝ๋ฉ
public class Category: NSObject, NSSecureCoding { public static var supportsSecureCoding: Bool = true var type: String? var color: UIColor? var image: UIImage? init(type: String? = nil, color: UIColor? = nil, image: UIImage? = nil) { self.type = type self.color = color self.image = image } public func encode(with coder: NSCoder) { guard let type = type, let color = color, let image = image else { return } coder.encode(type as NSString, forKey: "type") coder.encode(color as UIColor, forKey: "color") coder.encode(image as UIImage, forKey: "image") } required public convenience init?(coder: NSCoder) { let type = coder.decodeObject(of: NSString.self, forKey: "type") as? String let color = coder.decodeObject(of: UIColor.self, forKey: "color") let image = coder.decodeObject(of: UIImage.self, forKey: "image") self.init(type: type, color: color, image: image) } }
-
NSSecureUnarchiveFromDataTransformer subclass๋ฅผ ์์ฑํ๊ณ ๋ฑ๋ก
- ๊ฐ ๋ณํ ํ๋ก์ธ์ค์์ ์ต์์ ํด๋์ค์ด๋ฏ๋ก allowedTopLevelClasses ๋ฐฐ์ด์ Category ํด๋์ค๋ฅผ ์ถ๊ฐ
- custom transformer ๋ฅผ ๋ฑ๋กํ๊ธฐ ์ํ ๋ฉ์๋
class CategoryTransformer: NSSecureUnarchiveFromDataTransformer { override class var allowedTopLevelClasses: [AnyClass] { return [Category.self] } static func register() { let className = String(describing: CategoryTransformer.self) let name = NSValueTransformerName(className) let transformer = CategoryTransformer() ValueTransformer.setValueTransformer(transformer, forName: name) } }
-
์์ฑํ data transformer ํ์ ํด๋์ค๋ฅผ Transformable ํ์ attribute์ ์ฐ๊ฒฐ
-
์ ์ง๋ณด์๋ฅผ ๊ณ ๋ คํ ๋์์ธ/ํ ๋ง ๋ฑ์ ํ์ผ ๊ด๋ฆฌ (ํ์ฅํ์ผ ์์ฑ๊ณผ ํจ์จ์ ์ธ ๊ด๋ฆฌ)
๐ก ๋ฌธ์ ์ํฉ: ํน์๋ ํฅํ ์ ์ง๋ณด์ ๋ฑ์ผ๋ก ์ธํด ๋์์ธ/ํ ๋ง ๋ฑ์ ๋ณ๊ฒฝ์ด ์ผ์ด๋ฌ์๋๋ฅผ ๋๋นํด, ๋์์ธ์ ์ธ ์์๋ฅผ ์ด๋ป๊ฒ ๋ฆฌํฉํ ๋งํ๊ธฐ ์ฝ๊ฒ ๊ด๋ฆฌํ ์ ์์๊น?
- ํ์ฅ(extension)์ ํตํ ๋ค์์คํ์ด์ค ์ง์ ๊ณผ ๋ค์์คํ์ด์ค์์ ์ ์ธํ ๊ตฌ์กฐ์ฒด๋ฅผ ๋ค์ ํ์์ ์ ์ธํด์ ์ธ์ ๋ ์ง ์๋ก์ด ๋์์ธ/ํ ๋ง ๋ณ๊ฒฝ ๊ฐ๋ฅํ๋๋ก ๊ด๋ฆฌ
extension UIImage {
static let mainIcon = MainIconTheme() // ์ ์ธ์ํ ๊ตฌ์กฐ์ฒด๋ง ๊ต์ฒดํ๋ฉด ๋จ
//...
}
struct MainIconTheme {
let all: UIImage = UIImage(systemName: "list.clipboard")!
let work: UIImage = UIImage(systemName: "text.book.closed")!
let music: UIImage = UIImage(systemName: "beats.headphones")!
let travel: UIImage = UIImage(named: "airplane")!
let study: UIImage = UIImage(named: "edit")!
let stuff: UIImage = UIImage(systemName: "house")!
let hobby: UIImage = UIImage(systemName: "paintpalette")!
let shopping: UIImage = UIImage(systemName: "cart")!
}
๋ฉ๋ชจ ์์ฑ ํ๋ฉด์์ ํค๋ณด๋์ ๋์ด๋งํผ ์ ์ฅํ๊ธฐ ๋ฒํผ ์ฌ๋ผ์ค๊ฒ ๊ตฌํํ๊ธฐ (ํค๋ณด๋์ ๋ฐ๋ฅธ ์ ๋๋ฉ์ด์ ์ ์ฉ)
๐ก ๋ฌธ์ ์ํฉ: ์ ์ฅํ๊ธฐ ๋ฒํผ์ด ํค๋ณด๋ ๋์ด์ ๋ฑ ๋ง๊ฒ๋ ์ฌ๋ผ์ค๊ฒ ํ๊ณ ์ถ์๋ฐ ์ด๋ป๊ฒ ํ ์ ์์๊น?
-
์ฝ๋๊ฐ ์๋ ์คํ ๋ฆฌ๋ณด๋๋ก ๋ฒํผ์ ์ ์ฝ์ ์ฃผ์๊ธฐ ๋๋ฌธ์ IBOutlet ์ผ๋ก ์ ์ฝ์ ์ฝ๋์ ์ฐ๊ฒฐํจ
-
keyboardWillShow(_:)
keyboardWillHide(_:)
ํจ์์ ๋ ธํฐํผ์ผ์ด์ ์ค์ -
ํค๋ณด๋๊ฐ ์ฌ๋ผ์ฌ ๋ ํญ๋ฐ์ ํค๋ณด๋์ height์ ๋์ ์ผ๋ก ๊ณ์ฐํ์ฌ ํด๋น ๋์ด๋งํผ ์ ์ฝ์ ์ฃผ๊ณ ,
-
ํค๋ณด๋๊ฐ ๋ด๋ ค๊ฐ ๋ ์ ์ฝ์ 0์ผ๋ก ์ฃผ๊ณ ์์ฐ์ค๋ฝ๊ฒ ๋ด๋ ค๊ฐ๋๋ก ์ ๋๋ฉ์ด์ ์ ๋ฃ์ด ๋ทฐ๋ฅผ ๋ค์ ๊ทธ๋ฆผ
// ๋ฒํผ์ ์์น๋ฅผ ๋์ ์ผ๋ก ๋ณ๊ฒฝํ๊ธฐ ์ํ ์ ์ฝ ์ฐ๊ฒฐ @IBOutlet weak var buttonBottomConstraint: NSLayoutConstraint! override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil) } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) NotificationCenter.default.removeObserver(self) } @objc private func keyboardWillShow(_ notification: Notification) { guard let tabBar = self.tabBarController?.tabBar else { return } let tabBarHeight = tabBar.frame.size.height guard let keyboardFrame = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else { return } let keyboardHeight = keyboardFrame.size.height buttonBottomConstraint.constant = keyboardHeight - tabBarHeight UIView.animate(withDuration: 0.3) { self.view.layoutIfNeeded() } } @objc private func keyboardWillHide(_ notification: Notification) { buttonBottomConstraint.constant = 0 UIView.animate(withDuration: 0.3) { self.view.layoutIfNeeded() } }
๋คํฌ๋ชจ๋๋ฅผ ์ง์ํ์ง ์๋ ์ปฌ๋ฌ์ ๋คํฌ๋ชจ๋ ๋์ (๋คํฌ๋ชจ๋ ์ง์)
๐ก ๋ฌธ์ ์ํฉ: ์ ์ ์ ์ฅ์์์ ํธ๋ฆฌํ ์ฌ์ฉ ๊ฒฝํ์ ์ ๊ณต์ ์ํ ๋คํฌ๋ชจ๋ ๋์์ ํ๊ณ ์ถ์๋ฐ ์ด๋ป๊ฒ ํด์ผ ํ ๊น?
- UI ๊ธฐ๋ณธ์ปฌ๋ฌ๋ ๋คํฌ๋ชจ๋๋ฅผ ์ง์ํ์ง๋ง, ์ปค์คํ
์ปฌ๋ฌ๋ ๋คํฌ๋ชจ๋๋ฅผ ์ง์ํ์ง ์์
-
Assets
์Color Set
์ ๋ผ์ดํธ๋ชจ๋์ ๋คํฌ๋ชจ๋์ ์์์ ์ง์ ํ์ฌ ๋์ํจ// ๋คํฌ๋ชจ๋์ผ ๋ ๊ธ์์ ๋ณ๊ฒฝ textView.textColor = UIColor { (traitCollection: UITraitCollection) -> UIColor in if traitCollection.userInterfaceStyle == .dark { return UIColor.white } else { return UIColor.black }
-
-
๋ฒ๊ทธ ์์ b201ba4
- ์นดํ ๊ณ ๋ฆฌ์์ ์์ ํ๋ ํ๋ฉด ์ง์ ์ ๋ ์ง ๋๋ค์ผ๋ก ๋ณด์ด๋ ๊ฒ ์์
- ๋ชจ์๋ณด๊ธฐ์์ ์์ ํ๋ ํ๋ฉด ์ง์ ์ ์นดํ ๊ณ ๋ฆฌ ๋๋ค์ผ๋ก ๋ณด์ด๋ ๊ฒ ์์
- ๋ฏธ๋ฆฌ๋ณด๊ธฐ ๋ฉ๋ชจ์ ๋ณธ๋ฌธ์ ๋ฉ๋ชจ๊ฐ ๋ค๋ฅธ ๊ฒ ์์
- ๋ฉ๋ชจ ์์ ์ ์นดํ ๊ณ ๋ฆฌ ์ง์ ํ์ง ์์ผ๋ฉด ์ ๋ฌด๋ก ์ง์ ๋๋ ๊ฒ ์์
-
delete ์๋๋ ๊ฒ ์์ c16406b