본문 바로가기

iOS

컬렉션 뷰에서 데이터를 사용할 때 struct?, class?

728x90
반응형
SMALL

컬렉션 뷰에서 데이터를 사용할 때는 보통 클래스를 사용하는 것이 좋습니다. 이는 클래스가 참조 타입이기 때문에, 여러 곳에서 해당 데이터에 대한 참조를 공유할 수 있기 때문입니다.

반면에, 스트럭트는 값 타입이기 때문에 인스턴스를 복사하면 해당 데이터를 복사하게 됩니다. 그렇기 때문에 컬렉션 뷰에서 데이터를 사용할 때 스트럭트를 사용하면, 데이터를 복사하는 과정이 불필요하게 반복될 수 있습니다.

하지만, 데이터의 크기가 작고 빈번하게 생성되고 삭제되는 경우에는 스트럭트를 사용할 수도 있습니다. 이러한 경우 스트럭트를 사용하면 인스턴스 생성 및 소멸에 대한 부담을 줄일 수 있습니다.

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
}

하지만 두 방식에는 앞서 말씀드린 차이가 있습니다.

  1. Mutability
  2. Pass-by-value vs Pass-by-reference

따라서, 클래스는 내부의 프로퍼티 값을 변경할 수 있고, 다른 변수나 상수가 같은 객체를 참조하게 됩니다. 반면, 구조체는 내부의 프로퍼티 값을 변경할 수 없으며, 복사해서 다른 변수나 상수에 할당하면 값을 복사합니다.

728x90
반응형
LIST

'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