컬렉션 뷰에서 데이터를 사용할 때는 보통 클래스를 사용하는 것이 좋습니다. 이는 클래스가 참조 타입이기 때문에, 여러 곳에서 해당 데이터에 대한 참조를 공유할 수 있기 때문입니다.
반면에, 스트럭트는 값 타입이기 때문에 인스턴스를 복사하면 해당 데이터를 복사하게 됩니다. 그렇기 때문에 컬렉션 뷰에서 데이터를 사용할 때 스트럭트를 사용하면, 데이터를 복사하는 과정이 불필요하게 반복될 수 있습니다.
하지만, 데이터의 크기가 작고 빈번하게 생성되고 삭제되는 경우에는 스트럭트를 사용할 수도 있습니다. 이러한 경우 스트럭트를 사용하면 인스턴스 생성 및 소멸에 대한 부담을 줄일 수 있습니다.
Why?
클래스의 객체 생성 및 소멸과 관련된 오버헤드가 있기 때문입니다. 클래스는 객체를 생성하면 객체를 위한 메모리를 동적으로 할당하고, 생성자를 호출하고, 객체를 초기화합니다. 객체가 삭제될 때는 소멸자가 호출되고 할당된 메모리가 해제됩니다. 반면에, 스트럭트는 생성 및 삭제가 단순합니다. 객체 생성시 메모리 할당 및 초기화 작업만 수행하고, 삭제시에는 단순히 메모리를 해제합니다.
예제코드
//
// ViewController.swift
// TestUIKit
//
// Created by Byeon jinha on 2023/04/11.
//
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Create the collection view layout
let layout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: 100, height: 100)
layout.minimumInteritemSpacing = 10
layout.minimumLineSpacing = 10
layout.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
// Create the collection view
let collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
collectionView.backgroundColor = .white
collectionView.dataSource = self
collectionView.delegate = self
collectionView.register(MyCollectionViewCell.self, forCellWithReuseIdentifier: "MyCell")
// Add the collection view to the view hierarchy
view.addSubview(collectionView)
// People에 데이터 추가
let person1 = Person(name: "John", age: 25)
let person2 = Person(name: "Jane", age: 30)
let people = People()
people.addPerson(person1)
people.addPerson(person2)
self.people = people
}
var people: People?
}
class Person {
let name: String
let age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
class People {
var people: [Person] = []
func addPerson(_ person: Person) {
people.append(person)
}
func removePerson(at index: Int) {
people.remove(at: index)
}
}
class MyCollectionViewController: UICollectionViewController {
var people = People()
override func viewDidLoad() {
super.viewDidLoad()
// People에 데이터 추가
let person1 = Person(name: "John", age: 25)
let person2 = Person(name: "Jane", age: 30)
people.addPerson(person1)
people.addPerson(person2)
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return people.people.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCell", for: indexPath) as! MyCollectionViewCell
// People에서 데이터 가져와서 cell에 표시
let person = people.people[indexPath.row]
cell.nameLabel.text = person.name
cell.ageLabel.text = "\(person.age)"
return cell
}
}
extension ViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return people?.people.count ?? 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCell", for: indexPath) as! MyCollectionViewCell
// People에서 데이터 가져와서 cell에 표시
if let person = people?.people[indexPath.row] {
cell.nameLabel.text = person.name
cell.ageLabel.text = "\(person.age)"
}
return cell
}
}
extension ViewController: UICollectionViewDelegate {
}
import UIKit
class MyCollectionViewCell: UICollectionViewCell {
let nameLabel: UILabel
let ageLabel: UILabel
override init(frame: CGRect) {
nameLabel = UILabel(frame: CGRect(x: 0, y: 0, width: frame.width, height: frame.height * 0.7))
ageLabel = UILabel(frame: CGRect(x: 0, y: frame.height * 0.7, width: frame.width, height: frame.height * 0.3))
super.init(frame: frame)
nameLabel.textAlignment = .center
ageLabel.textAlignment = .center
contentView.addSubview(nameLabel)
contentView.addSubview(ageLabel)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func configure(with person: Person) {
nameLabel.text = person.name
ageLabel.text = "\(person.age)"
}
}
이 코드를 아래와 같이 Person 클랙스를 스트럭트로 바꿔도 잘 실행됩니다.
//class Person {
// let name: String
// let age: Int
//
// init(name: String, age: Int) {
// self.name = name
// self.age = age
// }
//}
struct Person {
let name: String
let age: Int
}
하지만 두 방식에는 앞서 말씀드린 차이가 있습니다.
- Mutability
- Pass-by-value vs Pass-by-reference
따라서, 클래스는 내부의 프로퍼티 값을 변경할 수 있고, 다른 변수나 상수가 같은 객체를 참조하게 됩니다. 반면, 구조체는 내부의 프로퍼티 값을 변경할 수 없으며, 복사해서 다른 변수나 상수에 할당하면 값을 복사합니다.
'iOS' 카테고리의 다른 글
intrinsicContentSize (0) | 2023.04.12 |
---|---|
(iOS) Chat GPT 사용해보기 (0) | 2023.04.12 |
Static dispatch, Dynamic dispatch (0) | 2023.04.11 |
iOS APP 화면 구성 (0) | 2023.04.11 |
NSObject (0) | 2023.04.11 |