본문 바로가기

iOS/Deep dive!!!

[Swift/UIkit] dequeueReusableCell(withIdentifier:) in TableView과 문제점

 

 



테이블 뷰와 테이블 뷰 셀의 관계

 

특정 데이터들에 의해 테이블 뷰 셀이 구성됩니다.

그렇게 구성된 여러개의 셀이 tableView(_: cellForRowAt:)에 의해 tableView의 Cell로 삽입됩니다.

이때 데이터들은 단순히 손으로 셀 수도 있지만 모바일 화면에 내려도 내려도 끝 없을 정도로 수없이 많은 데이터에 의해 테이블의 셀이 구성될 수도 있습니다.

 

소량으로 구현된 테이블 뷰

 

단순히 몇개의 테이블 셀을 구성할 때는 굳이 dequeueReusableCell(withIdentifier:)를 사용하지 않아도 됩니다.

하지만 다량의 데이터 소스를 cell에 등록하여 데이터 처리를 하고 보여줄 때는 dequeueReusableCell(withIdentifier:)가 필요로 합니다.

데이터 소스에 따라 더 많은 셀을 구현할 수 있다.

 

사용자는 위에 동영상처럼 생각보다 빠른 속도로 많은 정보들을 내려가면서 훑지 않습니다.

 

이렇게 다량의 데이터는 dequeueReusableCell(withIdentifier:)나 dequeueReusableCell(withidentifier:for:)를 통해 다루어 지지 않는다면.

tableView의 호출 시점에 데이터를 담은 클래스 타입의 다량의 배열이 즉시 할당될 것입니다. 각각의 cell마다 그림등의 이미지 데이터가 있다면 상당한 메모리가 사용됩니다.

 

예를들어 50,000개의 셀의 데이터가 담긴 배열이 메모리에 할당 되었다고 가정했을 때.

사용자는 화면을 3~4페이지 정도 내린다면 사용자는 약 20~40개의 셀만 보고 다른 화면으로 휙 넘어가 버린다면, 남은 49950 개의 데이터가 낭비된 것이라 볼 수 있습니다. 따라서 테이블 View가 호출된다고 화면에 당장 보이지 않는 49990개의 모든 cell에 대해서 사용자가 화면을 내리면서 (나 더 보고 싶은뎅? ~ )신호를 보낼 때, 그때 셀을 재사용해서 호출하면 메모리가 부담스러워하지 않아 메모리가 좋아할 것입니다.

이때 사용되는 것이 dequeueReusableCell(withIdentifier:) 메서드 입니다.


why use dequeueReusableCell(withIdentifier:)?

 

테이블 뷰에 사용되는 UITableViewCell은 index path를 통해 직접 확인 할 수도, 구현 할 수도 있습니다.

위에서 언급한 바와 같이 다량의 데이터를 다룰 때는 table view의 dequeueReusableCell(withIdentnfier:) , dequeueReusableCell(withIdentifier:for:) 메소드를 사용하면 Cell을 구현하거나, 재사용 됩니다.

 

table view는 Reuse를 위해 queue 또는 list를 통해 UITableViewCell을 관리합니다.


func tableView(_ tableView : UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
	let cell = UITableViewCell()
    ...
}

이 함수를 통해 table view의 cell을 생성하는데, 

deque 를 한 재사용 cell을 사용하지 않을 경우(위에서 생성한 cell인 경우) 위에서 언급한 바와 같이 사용하지도 않은 사용하지 않을 희박한 데이터까지 다량으로 메모리에 할당 될 것이기에

    let cell = tableView.dequeueReusableCell(withIdentifier: "myCell" , for : indexPath)
    또는
    let cell = tableView.dequeueReusableClee(withIdentifier: "myCell") ?? 
    				UITableViewCell(style: .defualt, reusIdentifier: "myCell")

이 두가지 방식으로 재사용 큐 셀을 통해 cell을 구현해야 합니다.

 

이 방식은 사용자가 사용할 정보, 소량의 데이터만 우선적으로 큐에서 꺼내집니다. 이후 위로 또는 아래로 화면에서 멀어질 경우(스크롤 될 경우) 다시 큐에 저장됩니다.

 

cell을 구현하는 방식은 새로운 것을 만들거나, 기존에 있던 것을 호출하거나 nil 타입이 있는데,

 

dequeueReusableCell(withIdentifier:)을 호출하게 되면 tableView는 특정 식별자가 있는 큐에서 Cell을 pop하려합니다. 그렇지 않을 경우 create로 cell을 반환합니다.

 


dequeueReusableCell(withIdentifier:) 과 dequeueReusableCell(withIdentifier:for:) 의 차이점은 반환하는 Cell이 nil 인지 아닌지 또한 특정 indexPath를 필요로 한다는 차이가 있습니다.


prepareForReuse() 는 언제..?

 

만일 호출된 cell이 특정 식별자에 의해 관리되고 있던 deQueue이면 dequeueReusableCell(withIdentifier:) 대신 cell의 prepareForReuse()메소드를 호출합니다!!

 

그래서 이미지 로딩과 같은 잠재적 수행 이슈를 피하려면 재사용으로 재 호출 될 Cell이 컨텐츠와 관련없거나 네트워크가 느려서 이미지가 제대로 로딩되지 않는다면 reset or nil처리 시킬 수 있습니다.

 

왜냐?! tableView의 delelgate 메서드로 사용되는 dequeueReusableCell(withIdentifier:)를 통해 셀은 reuse할 수 있게 되기 때문에 prepareForReuse()메서드를 통해 cell을 다룰수 있게 됩니다.

 

근데근데 .. 맨 초반에 예시와 같이 셀의 데이터에 image 등의 데이터가 있으면 사용자가 스크롤을 아래로 힘 껏 내렸다 다시 힘껏 올렸을 때 재사용 큐에 들어갔던 따근따근한 Cell이 다시 pop 되서 화면에 호출 될 때 사용자의 스크롤이 너무 빨라 이미지가 로딩이 잘 안될 수 있기에 prepareForReuse()메소드를 사용하면 된닷

 

visit my github

 

728x90