swift coredata - feat : tableView storyBoard 코드로 띄우기
완성화면
스토리보드
모델 관계
ViewController.swift - 리스트 화면
import CoreData
import UIKit
class ViewController: UIViewController, UITableViewDelegate , UITableViewDataSource {
@IBOutlet weak var tableView: UITableView!
//데이터 소스 역할을 할 배열 변수
lazy var list:[NSManagedObject] = {
return self.fetch()
}()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.list.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//데이터 가져오기
let record = self.list[indexPath.row]
let title = record.value(forKey: "title") as? String
let contents = record.value(forKey: "contents") as? String
//셀을 생성하고 값 대입
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")!
cell.textLabel?.text = title
cell.detailTextLabel?.text = contents
return cell
}
//행 수정 타입 : 삭제
func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
return .delete
}
//행 밀어서 수정 완료
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
let object = self.list[indexPath.row]
if self.delete(object: object){
//코어 데이터에서 삭제되면 배열 목록과 테이블 뷰의 행도 삭제
self.list.remove(at: indexPath.row)
self.tableView.deleteRows(at: [indexPath], with: .fade)
}
}
//행 클릭 + 팝업창 + 수정
//행선택시 팝업창 띄우고 수정하기
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("didSelectRowAt 선택")
//선택된 행에 대한 데이터 가져옴
let object = self.list[indexPath.row]
let title = object.value(forKey: "title") as? String
let contents = object.value(forKey: "contents") as? String
let alert = UIAlertController(title: "게시글 수정", message: nil, preferredStyle: .alert)
alert.addTextField(configurationHandler: {
$0.text = title
})
alert.addTextField(configurationHandler: {
$0.text = contents
})
alert.addAction(UIAlertAction(title: "취소", style: .cancel, handler: nil))
alert.addAction(UIAlertAction(title: "save", style: .default, handler: { (_) in
guard let title = alert.textFields?.first?.text , let contents = alert.textFields?.last?.text else{
return
}
//값을 수정하는 메소드 호출, 성공시 테이블 뷰 리로드
let check = self.edit(object: object, title: title, contents: contents)
if check == true {
let cell = self.tableView.cellForRow(at: indexPath)
cell?.textLabel?.text = title
cell?.detailTextLabel?.text = contents
//수정된 셀을 첫번째로 이동
let firstIndexRow = IndexPath(item: 0, section: 0)
self.tableView.moveRow(at: indexPath, to: firstIndexRow)
//self.tableView.reloadData()
}
}))
self.present(alert, animated: false, completion: nil)
}
//자세히 보기 - 악세사리
func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
print("악세사리 선택")
//스토리보드 identifire 로 화면 전환
let object = self.list[indexPath.row]
//let uvc = self.storyboard?.instantiateViewController(identifier: "LogVC") as! LogVC
let uvc = self.storyboard?.instantiateViewController(withIdentifier: "LogVC") as! LogVC
uvc.board = object as? BoardMo
self.show(uvc, sender: self)
}
override func viewDidLoad() {
super.viewDidLoad()
//델리게이트 + 데이터 소스 설정
self.tableView.delegate = self
self.tableView.dataSource = self
//바 버튼 아이템 추가
let addBtn = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(add(_:)))
self.navigationItem.rightBarButtonItem = addBtn
}
//데이터 추가
@objc func add(_ sender:Any){
//팝업창
let alert = UIAlertController(title: "게시글 등록", message: nil, preferredStyle: .alert)
//팝업창에 텍스트 필드 추가
alert.addTextField(configurationHandler: {
$0.placeholder = "제목"
})
alert.addTextField(configurationHandler: {
$0.placeholder = "내용"
})
//버튼 + 이벤트 1
alert.addAction(UIAlertAction(title: "cancel", style: .cancel, handler: nil))
//버튼 + 이벤트 2
alert.addAction(UIAlertAction(title: "저장", style: .default, handler: { (_) in
//팝업창의 Alert의 텍스트 필드 값 가져오기
guard let title = alert.textFields?.first?.text, let contents = alert.textFields?.last?.text else{
return
}
//값을 저장, 성공하면 테이블 리로드
if self.save(title: title, contents: contents) == true{
print("저장완료")
self.tableView.reloadData()
}
})) //alert.addAction - end
self.present(alert, animated: false, completion: nil)
}
//전체 조회
func fetch() -> [NSManagedObject] {
//앱델리게이트 객체 참조
let appDelegate = UIApplication.shared.delegate as! AppDelegate
//관리 객체 컨텍스트 참조
let context = appDelegate.persistentContainer.viewContext
//요청 객체 생성
//코어 데이터에서 데이터를 가져올 때 요청 사항을 정의한 NSFetchRequest 객체가 사용됩니다.
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Board")
//정렬 속성 설정 - false 내림차순, true 오름차순
let sort = NSSortDescriptor(key: "regdate", ascending: false)
fetchRequest.sortDescriptors = [sort]
//데이터 가져오기
//fetch(_:) 메서드는 원하는 데이터를 한꺼번에 가져올 때 호출합니다.
//이 메서드로 반환되는 관리 객체의 데이터는 실제로 참조하기 전에는 로드되지 않습니다.
let result = try! context.fetch(fetchRequest)
return result
}
//저장
func save(title:String, contents:String) -> Bool {
//앱델리게이트 객체 참조
let appDelegate = UIApplication.shared.delegate as! AppDelegate
//관리 객체 컨텍스트 참조
let context = appDelegate.persistentContainer.viewContext
//관리 객체 생성
//관리 객체는 생성과 동시에 컨텍스트 관리하에 있어야 하기 때문에
//아래와 같은 방법으로 객체를 생성한다.
let object = NSEntityDescription.insertNewObject(forEntityName: "Board", into: context)
object.setValue(title, forKey: "title")
object.setValue(contents, forKey: "contents")
object.setValue(Date(), forKey: "regdate")
//Log 관리 객체 생성, 어트리뷰트 값 대입
let logObject = NSEntityDescription.insertNewObject(forEntityName: "Log", into: context) as! LogMo
logObject.regdate = Date()
logObject.type = LogType.create.rawValue
//게시글 객체의 logs 속성에 새로 생성된 로그 객체 추가
(object as! BoardMo).addToLogs(logObject)
//영구 저장소에 커밋되고 나면 , list 프로퍼티에 추가
do {
try context.save()
//배열의 제일 뒤에 추가
//self.list.append(object)
self.list.insert(object, at: 0) //0번째 인덱스에 데이터 삽입
return true
} catch {
//동기화 실패하면 RollBack
context.rollback()
return false
}
}//func save() - end
//파일 삭제
/*
코어 데이터의 삭제 과정은
컨텍스트에서 해당 데이터를 삭제하고
컨텍스트의 변경 사항을 영구 저장소에 동기화합니다.
이 과정은 삭제가 아니라 변경을 반영하는 과정이기 때문에 save() 메서드를 호출하게 됩니다.
*/
func delete(object: NSManagedObject) -> Bool{
//앱 델리게이트 객체 참조
let appDelegate = UIApplication.shared.delegate as! AppDelegate
//관리 객체 컨텍스트 참조
let context = appDelegate.persistentContainer.viewContext
//컨텍스트로부터 해당 객체 삭제
context.delete(object)
//영구 저장소에 커밋
do {
try context.save()
return true
} catch{
context.rollback()
return false
}
}
//수정
func edit(object:NSManagedObject , title:String , contents:String) -> Bool{
//앱 델리게이트 객체 참조
let appDelegate = UIApplication.shared.delegate as! AppDelegate
//관리 객체 컨텍스트 참조
let context = appDelegate.persistentContainer.viewContext
//관리 객체의 값을 수정
object.setValue(title, forKey: "title")
object.setValue(contents, forKey: "contents")
object.setValue(Date(), forKey: "regdate")
//Log 관리 객체 생성, 어트리뷰트 값 대입
let logObject = NSEntityDescription.insertNewObject(forEntityName: "Log", into: context) as! LogMo
logObject.regdate = Date()
logObject.type = LogType.edit.rawValue
//게시글 객체의 logs 속성에 새로 생성된 로그 객체 추가
(object as! BoardMo).addToLogs(logObject)
//영구저장소에 커밋
do {
try context.save()
self.list = self.fetch()
return true
} catch {
context.rollback()
return false
}
}
}
LogVC.swift -로그화면
import CoreData
import UIKit
//로그 타입
public enum LogType : Int16{
case create = 0
case edit = 1
case delete = 2
}
//확장
extension Int16{
func toLogType() -> String {
switch self {
case 0:
return "생성"
case 1:
return "수정"
case 2:
return "삭제"
default:
return ""
}
}
}
class LogVC: UITableViewController {
var board : BoardMo! //게시글 정보를 전달 받을 변수
/*
로그 목록을 읽어오기 위해서 fetch() 메서드를 호출하지 않아도 됩니다.
전달받은 board 변수 내부에 로그 목록에 대한 참조가 이미 포함되어 있기 때문입니다.
array 속성은 NSSet, NSOrderedSet 객체를 배열 형태로 제공합니다.
logs 속성을 배열 형태로 처리해서 [LogMo] 타입으로 캐스팅합니다.
*/
lazy var list : [LogMo]! = {
return self.board.logs?.array as! [LogMo]
}()
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.title = self.board.title ?? "없음.."
}
// MARK: - Table view data source
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.list.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let row = self.list[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "logcell")!
cell.textLabel?.text = "\(row.regdate!)에 \(row.type.toLogType()) 되었습니다."
cell.textLabel?.font = UIFont.systemFont(ofSize: 12)
return cell
}
}
참고
https://blog.naver.com/go4693/221398724820
'아이폰 개발 > Swift' 카테고리의 다른 글
swift AutoLayout 1 - 소개 (0) | 2021.03.29 |
---|---|
swift - 회원가입화면 예제 feat : pickerViewController + 인디케이터 + 이미지처리 (0) | 2021.03.27 |
swift 프로퍼티 리스트 - feat: pickerView & tableView (0) | 2021.03.26 |
swift - alert 커스터마이징 feat: 지도, 이미지, 테이블뷰, 슬라이더 (1) | 2021.03.25 |
swift 계정 Profile 화면 디자인 예제 (0) | 2021.03.25 |