반응형
coreData클래스와 우리가 만들었던 클래스가 충돌하기 때문에, 우리가 만들었던 클래스를 주석처리한다.
//
// Model.swift
// NhMemo
//
import Foundation
//class Memo {
// var content:String
// var insertDate:Date
//
// init(content:String) {
// self.content = content
// insertDate = Date()
// }
//
// //더미 데이터
// static var dummyMemoList = [
// Memo(content: "dw memo desu"),
// Memo(content: "so death gga?")
//
// ]
//}
2. 코드가 불필요하게 복잡해질 수 있으니, AppDelegate 파일의 주석 처리되어 있는
// MARK: - Core Data stack
의 밑의 코드를 모두 복사한 후, DataManager이라는 swift파일을 만들어준다.
//
// DataManager.swift
// NhMemo
import Foundation
import CoreData
//싱글톤
class DataManager {
//공유 인스턴스를 저장할 타입 프로퍼티 추가
static let shared = DataManager()
//생성자 : 이렇게 하면, 하나의 인스턴스로 앱 전체에 공유할 수 있다.
private init() {
}
//메모를 저장할 배열을 생성 후 빈배열로 만듬.
var memoList = [Memo]()
//새로운 속성 추가 : 대부분의 작업은 context가 담당
var mainContext: NSManagedObjectContext {
return persistentContainer.viewContext
}
func fetchMemo() {
//데이터베이스에서 데이터를 읽기 위해 fetch request를 만들어야한다.
let request:NSFetchRequest<Memo> = Memo.fetchRequest()
//데이터 정렬해주어야함 : 내림차순 정렬
let sortByDateDesc = NSSortDescriptor(key: "insertDate", ascending: false)
request.sortDescriptors = [sortByDateDesc]
//fetch 메소드는 context가 제공하는 fetch 메소드를 사용.
do {
memoList = try mainContext.fetch(request)
}catch {
print(error)
}
}
//메모추가
func addNewMemo(_ memo:String?) {
//코어 데이터
let newMemo = Memo(context: mainContext)
newMemo.content = memo
newMemo.insertDate = Date()
//메모 호출
memoList.insert(newMemo, at: 0)
//메모 저장 컨텍스트
saveContext()
}
//MARK: - Core Data stack
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "NhMemo")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
// MARK: - Core Data Saving support
func saveContext () {
let context = persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
}
3. compostViewController에서 에러가 나는 부분 주석처리
//
// ComposeViewController.swift
// NhMemo
//
import UIKit
class ComposeViewController: UIViewController {
//cancel 버튼 연결
@IBAction func close(_ sender: Any) {
//첫번째 파라미터 : true전달 시, 실행
//두번째 파라미터 : 어떤 함수를 실행시키고 싶을 때, 클로저로
dismiss(animated: true, completion: nil)
}
//textView 저장을 위한 연결
@IBOutlet weak var memoTextview: UITextView!
//save 버튼 연결
@IBAction func save(_ sender: Any) {
//저장 버튼 클릭 시, memo안에 텍스트 저장 및 조건문
guard let memo = memoTextview.text,
memo.count > 0 else {
//확장클래스 가져옴. 사용자가 메모를 입력하지 않을 시, 경고창 뜸
alert(message: "메모를 입력하세요.")
return
}
//guard 다음에 실행 됨.
// let newMemo = Memo(content: memo)
// //메모 저장
// Memo.dummyMemoList.append(newMemo)
DataManager.shared.addNewMemo(memo)
//화면 닫기 전, notification 전달 (update를 위한 전달 broadcast)
NotificationCenter.default.post(name: ComposeViewController.newMemoDidInsert, object: nil)
//창 닫음
dismiss(animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
extension ComposeViewController {
//notification : 이름으로 구분
static let newMemoDidInsert = Notification.Name(rawValue: "newMemoDidInsert")
}
4. memo list table view controller 에러 수정
//
// MemoListTableViewController.swift
// NhMemo
//
import UIKit
class MemoListTableViewController: UITableViewController {
//날짜 포맷 (클로저 사용)
let formatDate:DateFormatter = {
let f = DateFormatter()
f.dateStyle = .long //long으로 출력
f.timeStyle = .short
f.locale = Locale(identifier: "Ko_kr") //한글로 변경
return f
}()
//view가 화면에 표시되기전에 실행 됨. 음.. 안드로이드로 치면,, onCreate?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
DataManager.shared.fetchMemo()
tableView.reloadData()
}
var token: NSObjectProtocol?
//옵저버 해제
deinit {
if let token = token {
NotificationCenter.default.removeObserver(token)
}
}
//세그웨이에 연결된 화면을 생성하고, 화면을 전환하기 직전에 호출 됨. sender을 활용! (몇번째 cell을 클릭했는지 계산해야함.)
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let cell = sender as? UITableViewCell,
let indexPath = tableView.indexPath(for: cell) { // 몇번째 cell인지 확인 할 수 있음.
//목록화면과 보기화면 접근 가능.
//segue를 실행하는 화면을 source라고 함, 새롭게 표시되는 화면을 destination이라고 함.
//타입 캐스팅 해야 함.
if let vc = segue.destination as? DetailViewController {
vc.memo = DataManager.shared.memoList[indexPath.row]
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
//notification, queue : ui업데이트 메인쓰레드, 4번째 파라미터에 전달된 클로저가 3번째 파라미터에 전달되어 실행됨.
//옵저버 해제 안하면 메모리 낭비!!
token = NotificationCenter.default.addObserver(forName: ComposeViewController.newMemoDidInsert, object: nil, queue: OperationQueue.main)
{ [weak self] (noti) in
//테이블 뷰 리로드
self?.tableView.reloadData()
}
}
// MARK: - Table view data source
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return DataManager.shared.memoList.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
// Configure the cell...
let target = DataManager.shared.memoList[indexPath.row]
cell.textLabel?.text = target.content
cell.detailTextLabel?.text = formatDate.string(for: target.insertDate)
return cell
}
}
반응형
'개발언어 > Swift' 카테고리의 다른 글
스위프트 네비게이션 컨트롤러(navigation controller) (0) | 2022.01.11 |
---|---|
스위프트 메모장 코드 뜯기 (appdelegate, plist, scenedelegate 역할) (0) | 2022.01.07 |
스위프트 메모장 만들기 7 (줄 바꿈 기능) (0) | 2022.01.01 |
스위프트 메모장 만들기 6 (목록화면 to 보기화면) (0) | 2021.12.31 |
스위프트 메모장 만들기 5 (메모 보기 화면 ) (0) | 2021.12.29 |