-
Notifications
You must be signed in to change notification settings - Fork 0
[Refactor] 파편화된 Content, Comment 엔티티 통합 및 홈, 상세, 프로필 화면에 적용 (Content) #267
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Walkthrough도메인 모델을 ContentTemp/CommentTemp로 전환하고 Likable 프로토콜을 추가했으며, 매퍼·레포지토리·유즈케이스·프레젠테이션 전반에서 타입·시그니처·셀·퍼블리셔를 ContentTemp/Comment.swift/Likable.swift 기반으로 갱신하고 Xcode 프로젝트 파일 참조를 조정했습니다. (약 50단어) Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor U as User
participant HV as HomeViewController
participant HVM as HomeViewModel
participant UC as FetchContentListUseCase
participant CR as ContentRepository
participant NW as Network/API
participant MP as ContentMapper
U->>HV: 목록 요청
HV->>HVM: fetchContents(cursor)
HVM->>UC: execute(cursor)
UC->>CR: fetchContentList(cursor)
CR->>NW: GET /contents?cursor=...
NW-->>CR: [DTO]
CR->>MP: toDomain([DTO])
MP-->>CR: [ContentTemp]
CR-->>UC: [ContentTemp]
UC-->>HVM: [ContentTemp]
HVM-->>HV: Output.contents([ContentTemp])
HV->>HV: Diffable DataSource 업데이트
sequenceDiagram
autonumber
actor U as User
participant HDV as HomeDetailViewController
participant HDM as HomeDetailViewModel
participant UCP as FetchContentInfoUseCase
participant CR as ContentRepository
participant NW as Network/API
participant MP as ContentMapper
U->>HDV: 상세 진입(contentID)
HDV->>HDM: fetchContent(contentID)
HDM->>UCP: execute(contentID)
UCP->>CR: fetchContentInfo(contentID)
CR->>NW: GET /contents/{id}
NW-->>CR: FetchContent DTO
CR->>MP: toDomain(dto, id)
MP-->>CR: ContentTemp
CR-->>UCP: ContentTemp
UCP-->>HDM: ContentTemp
HDM-->>HDV: Output.content(ContentTemp?)
HDV->>Cell: configureCell(info: ContentTemp)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Assessment against linked issues
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limits.
🔭 Outside diff range comments (4)
Wable-iOS/Presentation/Home/View/HomeViewController.swift (3)
180-196: 셀에 저장되는 클로저가 self/cell을 강하게 잡아 순환 참조 및 메모리 누수 가능성contentImageViewTapHandler와 likeButtonTapHandler가 cell과 self를 강하게 캡처합니다. 셀은 이 핸들러를 프로퍼티로 오래 보유하므로 VC ↔ CollectionView ↔ Cell ↔ Closure ↔ VC의 사이클이 형성될 수 있습니다.
아래처럼 약한 캡처로 교체해 주세요.
- contentImageViewTapHandler: { - guard let image = cell.contentImageView.image else { - return - } - - self.navigationController?.pushViewController(PhotoDetailViewController(image: image), animated: true) - }, - likeButtonTapHandler: { - AmplitudeManager.shared.trackEvent(tag: .clickLikePost) - - self.didHeartTappedSubject.send((item.id, cell.likeButton.isLiked)) - }, + contentImageViewTapHandler: { [weak self, weak cell] in + guard let self = self, + let image = cell?.contentImageView.image else { return } + self.navigationController?.pushViewController(PhotoDetailViewController(image: image), animated: true) + }, + likeButtonTapHandler: { [weak self, weak cell] in + AmplitudeManager.shared.trackEvent(tag: .clickLikePost) + guard let self = self, + let isLiked = cell?.likeButton.isLiked else { return } + self.didHeartTappedSubject.send((item.id, isLiked)) + },
196-263: 설정 버튼 핸들러에서도 self를 약하게 캡처해 순환 참조 차단 필요설정 시트 액션 핸들러는 self를 다수 참조합니다. 약한 캡처와 초기 guard로 누수 가능성을 줄이세요.
아래처럼 변경을 권장합니다.
- settingButtonTapHandler: { - let viewController = WableBottomSheetController() + settingButtonTapHandler: { [weak self] in + guard let self = self else { return } + let viewController = WableBottomSheetController() @@ - if self.activeUserID == item.author.id { + if self.activeUserID == item.author.id { @@ - } else if self.isActiveUserAdmin ?? false { + } else if self.isActiveUserAdmin ?? false { @@ - } else { + } else { @@ - self.present(viewController, animated: true) + self.present(viewController, animated: true) },
288-296: 고스트 버튼 핸들러도 self 약한 캡처 필요UI 액션을 보관하는 셀 클로저 특성상 self를 약하게 캡처해야 안전합니다.
- ghostButtonTapHandler: { + ghostButtonTapHandler: { [weak self] in - AmplitudeManager.shared.trackEvent(tag: .clickGhostPost) - self.showGhostSheet(onCancel: { + AmplitudeManager.shared.trackEvent(tag: .clickGhostPost) + self?.showGhostSheet(onCancel: { - AmplitudeManager.shared.trackEvent(tag: .clickWithdrawghostPopup) - }, onPrimary: { message in - AmplitudeManager.shared.trackEvent(tag: .clickApplyghostPopup) - self.didGhostTappedSubject.send((item.id, item.author.id, message)) + AmplitudeManager.shared.trackEvent(tag: .clickWithdrawghostPopup) + }, onPrimary: { message in + AmplitudeManager.shared.trackEvent(tag: .clickApplyghostPopup) + self?.didGhostTappedSubject.send((item.id, item.author.id, message)) }) }Wable-iOS/Presentation/Profile/Other/View/OtherProfileViewController.swift (1)
207-218: 미사용 indexPath 파라미터와 셀 보관 클로저의 강한 캡처 수정 필요
- indexPath는 미사용이므로
_처리 권장.- contentImageViewTapHandler가 cell을 강하게 캡처합니다. [weak cell]로 순환 참조를 방지하세요.
- let contentCellRegistration = CellRegistration<ContentCollectionViewCell, ContentTemp> { - cell, indexPath, item in + let contentCellRegistration = CellRegistration<ContentCollectionViewCell, ContentTemp> { + cell, _, item in cell.configureCell( info: item, authorType: .others, cellType: .list, - contentImageViewTapHandler: { [weak self] in - guard let image = cell.contentImageView.image else { return } + contentImageViewTapHandler: { [weak self, weak cell] in + guard let image = cell?.contentImageView.image else { return } let photoDetailViewController = PhotoDetailViewController(image: image) self?.navigationController?.pushViewController(photoDetailViewController, animated: true) },
🧹 Nitpick comments (12)
Wable-iOS/Domain/Protocol/Likable.swift (1)
19-31: 토글 편의 메서드 제공을 제안합니다호출부 단순화를 위해 toggleLike() 제공을 고려해 보세요. 중복 분기 로직을 줄일 수 있습니다.
extension Likable { mutating func like() { @@ mutating func unlike() { @@ } + + mutating func toggleLike() { + isLiked ? unlike() : like() + } }Wable-iOS/Domain/Entity/Content.swift (2)
19-20: UserContent.contentInfo → ContentTemp로의 전환은 타당합니다만, 프로퍼티명은 여전히 contentInfo입니다타입이 ContentTemp로 바뀌었으니 프로퍼티명도 content 등으로 정리하면 가독성이 좋아집니다. 지금 상태는 타입/이름 불일치로 혼동 여지가 있습니다. 다음 단계에서 네이밍 변경을 고려해 주세요.
해당 네이밍 변경 시 호출부 영향 범위가 넓을 수 있으니, 매퍼/뷰모델/셀 구성부까지 빌드 검증 부탁드립니다.
39-53: ContentTemp 도입은 일관되고 깔끔합니다Identifiable/Hashable/Likable 채택으로 프리젠테이션과 상호작용(좋아요)까지 한 타입에 일원화된 점이 좋습니다.
한 가지 확인: title이 비Optional(String)입니다. 서버/DTO에서 title이 없을 수 있는 케이스가 없다면 OK입니다. 존재할 수 있다면 매핑 시 강제 언래핑이나 임의 기본값 주입 여부를 점검해주세요. 또한 Wrapper인 Content.isDeleted와 ContentTemp.isDeleted(옵셔널)로 삭제 상태의 이중 소스가 생길 수 있습니다. 궁극적으로는 Wrapper 제거 또는 단일 소스 유지로 정리하는 것이 안전합니다.
Wable-iOS/Presentation/Profile/Model/ProfileViewItem.swift (1)
10-15: commentList는 여전히 구 타입(UserComment)입니다 — CommentTemp로 동기화 권장콘텐츠 리스트가 ContentTemp로 통합된 것과 달리 댓글 리스트는 UserComment(내부에 CommentInfo)로 남아있어 두 모델이 혼재합니다. 일관성·매핑 복잡성을 고려하면 [CommentTemp]로의 통일을 권장합니다.
아래처럼 모델을 교체할 경우, 해당 뷰모델/유즈케이스/매퍼의 반환 타입과 셀 바인딩을 함께 점검해 주세요.
struct ProfileViewItem { var currentSegment: ProfileSegment = .content var profileInfo: UserProfile? var contentList: [ContentTemp] = [] var commentList: [CommentTemp] = [] // 제안 }Wable-iOS/Presentation/Home/View/HomeViewController.swift (2)
176-179: 미사용 파라미터(indexPath)로 인한 SwiftLint 경고 제거 제안cell registration 클로저에서 indexPath를 사용하지 않습니다. 린트 경고(unused_closure_parameter) 제거를 위해
_로 변경을 권장합니다.아래처럼 수정해 주세요.
- let homeCellRegistration = CellRegistration<ContentCollectionViewCell, ContentTemp> { - [weak self] cell, indexPath, item in + let homeCellRegistration = CellRegistration<ContentCollectionViewCell, ContentTemp> { + [weak self] cell, _, item in
448-455: DiffableDataSource 적용 후 reloadData 호출은 불필요 — 성능/애니메이션 개선snapshot 적용만으로 UI 반영이 충분합니다. reloadData는 불필요한 전체 리로드를 유발해 성능과 애니메이션에 악영향이 있습니다.
dataSource?.apply(snapshot) - collectionView.reloadData()Wable-iOS/Presentation/WableComponent/Cell/ContentCollectionViewCell.swift (1)
274-274: 옵셔널 처리 개선 제안
createdDate가 nil일 경우 함수가 조기 종료되어 셀이 구성되지 않습니다. 이는 UI에 빈 셀이 표시될 수 있습니다.- guard let createdDate = info.createdDate else { return } + let createdDate = info.createdDate ?? Date()또는 더 명시적인 처리:
- guard let createdDate = info.createdDate else { return } + guard let createdDate = info.createdDate else { + // 날짜가 없는 경우에도 최소한의 UI는 표시 + infoView.isHidden = true + return + }Wable-iOS/Presentation/Profile/Other/ViewModel/OtherProfileViewModel.swift (1)
89-91: 좋아요 상태 업데이트 로직 개선 필요SwiftLint 경고에 따라 삼항 연산자를 사용하여 void 함수를 호출하는 것은 권장되지 않습니다. 더 명확한 if-else 구문을 사용하세요.
await MainActor.run { var contentInfo = item.contentList[index] - isLiked ? contentInfo.unlike() : contentInfo.like() + if isLiked { + contentInfo.unlike() + } else { + contentInfo.like() + } item.contentList[index] = contentInfo }Wable-iOS/Presentation/Home/ViewModel/HomeDetailViewModel.swift (1)
329-342: 중복된 ContentTemp 생성 로직Ghost 상태 업데이트 시 ContentTemp 생성 로직이 중복되어 있습니다. 헬퍼 메서드로 추출하여 재사용성을 높이세요.
ContentTemp 생성 로직을 헬퍼 메서드로 추출:
private func createUpdatedContent( from content: ContentTemp, status: PostStatus? = nil, opacity: Opacity? = nil ) -> ContentTemp { return ContentTemp( id: content.id, author: content.author, text: content.text, title: content.title, imageURL: content.imageURL, isDeleted: content.isDeleted, createdDate: content.createdDate, isLiked: content.isLiked, likeCount: content.likeCount, opacity: opacity ?? content.opacity, commentCount: content.commentCount, status: status ?? content.status ) }그리고 사용:
-let updatedContent = ContentTemp( - id: content.id, - author: content.author, - text: content.text, - title: content.title, - imageURL: content.imageURL, - isDeleted: content.isDeleted, - createdDate: content.createdDate, - isLiked: content.isLiked, - likeCount: content.likeCount, - opacity: content.opacity, - commentCount: content.commentCount, - status: .ghost -) +let updatedContent = createUpdatedContent(from: content, status: .ghost)Wable-iOS/Presentation/Home/ViewModel/HomeViewModel.swift (3)
160-187: 좋아요 상태 업데이트 로직 개선 가능ContentTemp 생성 로직이 반복되고 있습니다. 헬퍼 메서드를 사용하여 코드 중복을 줄이세요.
private func updateContentLikeStatus( _ content: ContentTemp, isLiked: Bool ) -> ContentTemp { return ContentTemp( id: content.id, author: content.author, text: content.text, title: content.title, imageURL: content.imageURL, isDeleted: content.isDeleted, createdDate: content.createdDate, isLiked: isLiked, likeCount: isLiked ? content.likeCount + 1 : content.likeCount - 1, opacity: content.opacity, commentCount: content.commentCount, status: content.status ) }
201-201: SwiftLint 경고: where 절 사용 권장for 루프 내부의 단일 if 문 대신 where 절을 사용하세요.
-for i in 0..<updatedContents.count { - if updatedContents[i].author.id == userID { +for i in 0..<updatedContents.count where updatedContents[i].author.id == userID {Also applies to: 271-271
270-292: 밴 처리 시 중복 코드Ghost 처리와 유사한 로직이 반복됩니다. 공통 헬퍼 메서드로 추출하세요.
private func updateContentsStatus( _ contents: [ContentTemp], for userID: Int, status: PostStatus ) -> [ContentTemp] { return contents.map { content in if content.author.id == userID { return ContentTemp( id: content.id, author: content.author, text: content.text, title: content.title, imageURL: content.imageURL, isDeleted: content.isDeleted, createdDate: content.createdDate, isLiked: content.isLiked, likeCount: content.likeCount, opacity: content.opacity.reduced(), commentCount: content.commentCount, status: status ) } return content } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (20)
Wable-iOS.xcodeproj/project.pbxproj(8 hunks)Wable-iOS/Data/Mapper/ContentMapper.swift(4 hunks)Wable-iOS/Data/RepositoryImpl/ContentRepositoryImpl.swift(3 hunks)Wable-iOS/Domain/Entity/Comment.swift(2 hunks)Wable-iOS/Domain/Entity/Content.swift(2 hunks)Wable-iOS/Domain/Protocol/Likable.swift(1 hunks)Wable-iOS/Domain/RepositoryInterface/ContentRepository.swift(1 hunks)Wable-iOS/Domain/UseCase/Home/FetchContentListUseCase.swift(1 hunks)Wable-iOS/Domain/UseCase/Profile/FetchContentInfoUseCase.swift(1 hunks)Wable-iOS/Domain/UseCase/Profile/FetchUserContentListUseCase.swift(1 hunks)Wable-iOS/Presentation/Home/View/HomeDetailViewController.swift(13 hunks)Wable-iOS/Presentation/Home/View/HomeViewController.swift(9 hunks)Wable-iOS/Presentation/Home/ViewModel/HomeDetailViewModel.swift(8 hunks)Wable-iOS/Presentation/Home/ViewModel/HomeViewModel.swift(8 hunks)Wable-iOS/Presentation/Profile/Model/ProfileViewItem.swift(1 hunks)Wable-iOS/Presentation/Profile/My/View/MyProfileViewController.swift(2 hunks)Wable-iOS/Presentation/Profile/My/ViewModel/MyProfileViewModel.swift(3 hunks)Wable-iOS/Presentation/Profile/Other/View/OtherProfileViewController.swift(3 hunks)Wable-iOS/Presentation/Profile/Other/ViewModel/OtherProfileViewModel.swift(3 hunks)Wable-iOS/Presentation/WableComponent/Cell/ContentCollectionViewCell.swift(2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (12)
Wable-iOS/Domain/UseCase/Profile/FetchContentInfoUseCase.swift (4)
Wable-iOS/Domain/UseCase/Home/FetchContentListUseCase.swift (1)
execute(22-24)Wable-iOS/Domain/UseCase/Profile/FetchUserContentListUseCase.swift (1)
execute(18-24)Wable-iOS/Domain/UseCase/Home/CreateContentUseCase.swift (1)
execute(23-25)Wable-iOS/Domain/UseCase/Home/DeleteContentUseCase.swift (1)
execute(23-25)
Wable-iOS/Presentation/Profile/My/View/MyProfileViewController.swift (1)
Wable-iOS/Presentation/WableComponent/Cell/ContentCollectionViewCell.swift (1)
configureCell(257-341)
Wable-iOS/Domain/RepositoryInterface/ContentRepository.swift (1)
Wable-iOS/Data/RepositoryImpl/ContentRepositoryImpl.swift (4)
fetchContentInfo(57-64)fetchContentList(66-73)fetchUserContentList(75-82)fetchUserContentList(84-94)
Wable-iOS/Presentation/WableComponent/Cell/ContentCollectionViewCell.swift (1)
Wable-iOS/Presentation/WableComponent/Button/LikeButton.swift (1)
configureButton(47-70)
Wable-iOS/Presentation/Home/ViewModel/HomeViewModel.swift (2)
Wable-iOS/Presentation/Home/ViewModel/HomeDetailViewModel.swift (1)
transform(91-512)Wable-iOS/Domain/Entity/Opacity.swift (1)
reduced(72-78)
Wable-iOS/Presentation/Profile/Other/View/OtherProfileViewController.swift (1)
Wable-iOS/Presentation/WableComponent/Cell/ContentCollectionViewCell.swift (1)
configureCell(257-341)
Wable-iOS/Presentation/Home/View/HomeViewController.swift (1)
Wable-iOS/Presentation/WableComponent/Cell/ContentCollectionViewCell.swift (1)
configureCell(257-341)
Wable-iOS/Presentation/Home/ViewModel/HomeDetailViewModel.swift (5)
Wable-iOS/Domain/UseCase/Profile/FetchContentInfoUseCase.swift (1)
execute(22-24)Wable-iOS/Domain/UseCase/Home/FetchContentListUseCase.swift (1)
execute(22-24)Wable-iOS/Domain/UseCase/Profile/FetchUserContentListUseCase.swift (1)
execute(18-24)Wable-iOS/Domain/UseCase/Home/FetchGhostUseCase.swift (1)
execute(23-30)Wable-iOS/Data/Mapper/ErrorMapper.swift (1)
map(29-43)
Wable-iOS/Presentation/Profile/Other/ViewModel/OtherProfileViewModel.swift (1)
Wable-iOS/Data/RepositoryImpl/ContentRepositoryImpl.swift (2)
fetchUserContentList(75-82)fetchUserContentList(84-94)
Wable-iOS/Domain/UseCase/Profile/FetchUserContentListUseCase.swift (5)
Wable-iOS/Domain/UseCase/Profile/FetchContentInfoUseCase.swift (1)
execute(22-24)Wable-iOS/Domain/UseCase/Home/FetchContentListUseCase.swift (1)
execute(22-24)Wable-iOS/Domain/UseCase/Profile/FetchUserCommentListUseCase.swift (1)
execute(18-24)Wable-iOS/Domain/UseCase/Profile/FetchAccountInfoUseCase.swift (1)
execute(18-20)Wable-iOS/Domain/UseCase/Profile/FetchUserProfileUseCase.swift (1)
execute(18-24)
Wable-iOS/Data/RepositoryImpl/ContentRepositoryImpl.swift (2)
Wable-iOS/Data/Mapper/ErrorMapper.swift (2)
map(29-43)mapWableError(13-25)Wable-iOS/Data/Mapper/ContentMapper.swift (3)
toDomain(13-51)toDomain(53-93)toDomain(95-135)
Wable-iOS/Presentation/Profile/My/ViewModel/MyProfileViewModel.swift (1)
Wable-iOS/Data/RepositoryImpl/ContentRepositoryImpl.swift (2)
fetchUserContentList(75-82)fetchUserContentList(84-94)
🪛 SwiftLint (0.57.0)
Wable-iOS/Presentation/Profile/My/View/MyProfileViewController.swift
[Warning] 209-209: Unused parameter in a closure should be replaced with _
(unused_closure_parameter)
Wable-iOS/Presentation/Home/ViewModel/HomeViewModel.swift
[Warning] 201-201: where clauses are preferred over a single if inside a for
(for_where)
[Warning] 271-271: where clauses are preferred over a single if inside a for
(for_where)
Wable-iOS/Presentation/Profile/Other/View/OtherProfileViewController.swift
[Warning] 208-208: Unused parameter in a closure should be replaced with _
(unused_closure_parameter)
Wable-iOS/Presentation/Home/View/HomeViewController.swift
[Warning] 177-177: Unused parameter in a closure should be replaced with _
(unused_closure_parameter)
Wable-iOS/Presentation/Profile/Other/ViewModel/OtherProfileViewModel.swift
[Warning] 90-90: Using ternary to call Void functions should be avoided
(void_function_in_ternary)
Wable-iOS/Presentation/Profile/My/ViewModel/MyProfileViewModel.swift
[Warning] 121-121: Using ternary to call Void functions should be avoided
(void_function_in_ternary)
🔇 Additional comments (25)
Wable-iOS.xcodeproj/project.pbxproj (1)
165-166: 빌드 설정 연결 확인 완료 (Likable.swift/Comment.swift 등록 정상)
- Likable.swift가 파일 참조 및 Sources 빌드 단계에 정상 추가되었습니다.
- CommentInfo.swift → Comment.swift로의 참조 교체도 정상입니다.
특이사항은 없습니다. 머지해도 빌드 단계에서 문제 없을 것으로 보입니다.
혹시 남아있는 경로/심볼로 CommentInfo를 참조하는 곳이 있다면 정리 부탁드립니다(문자열 경로 하드코딩 등).
Also applies to: 172-172, 543-543, 557-557, 2952-2952
Wable-iOS/Presentation/Profile/Model/ProfileViewItem.swift (1)
13-13: Profile 화면에서 ContentTemp로 전환 LGTMcontentList를 [ContentTemp]로 바꿔 프리젠테이션 모델과 도메인 모델이 일치합니다. 이후 셀/뷰모델에서 Likable의 isLiked/likeCount를 직접 활용할 수 있어 단순해집니다.
Wable-iOS/Domain/UseCase/Home/FetchContentListUseCase.swift (1)
22-24: 콘텐츠 리스트 반환 타입 전환 OK리스트 유스케이스도 ContentTemp로 일관되게 마이그레이션되었습니다. Repository 위임 로직도 그대로여서 리스크 낮습니다.
Wable-iOS/Presentation/Home/View/HomeViewController.swift (1)
22-22: 타입 별칭 전환 적절Home 화면의 아이템 모델을 ContentTemp로 통일한 선택이 명확합니다. 이후 셀 구성, 상세 전환 등과 자연스럽게 맞물립니다.
Wable-iOS/Presentation/Profile/My/View/MyProfileViewController.swift (1)
26-26: Item.case content의 ContentTemp 전환 적절프로필 화면 아이템 모델도 ContentTemp로 통일되어 상위 레이어와 일관성이 확보되었습니다.
Wable-iOS/Presentation/Profile/Other/View/OtherProfileViewController.swift (1)
25-25: Item.case content의 ContentTemp 전환 적절Other 프로필 화면도 ContentTemp로 정리되어 셀/VM/유즈케이스와 정합성이 좋습니다.
Wable-iOS/Domain/UseCase/Profile/FetchUserContentListUseCase.swift (1)
12-12: 좋은 리팩토링입니다!
UserContent에서 통합된ContentTemp타입으로의 마이그레이션이 적절하게 이루어졌습니다. 이는 코드베이스 전반에 걸쳐 일관된 도메인 모델을 사용하도록 하는 좋은 개선사항입니다.Also applies to: 18-18
Wable-iOS/Presentation/WableComponent/Cell/ContentCollectionViewCell.swift (1)
258-258: ContentTemp로의 타입 변경이 적절합니다!
ContentInfo에서ContentTemp로의 마이그레이션과 함께 like 정보 접근 방식이info.like.status/info.like.count에서info.isLiked/info.likeCount로 단순화되었습니다. 이는 Likable 프로토콜과 일관된 구조입니다.Also applies to: 332-332
Wable-iOS/Presentation/Profile/My/ViewModel/MyProfileViewModel.swift (2)
109-109: Likable 프로토콜 활용이 훌륭합니다!
ContentTemp의like()/unlike()메서드를 활용한 좋아요 상태 업데이트가 깔끔하게 구현되었습니다. 이는 Likable 프로토콜의 장점을 잘 활용한 좋은 예시입니다.Also applies to: 120-122
164-167: 타입 변경이 올바르게 적용되었습니다
[UserContent]에서[ContentTemp]로의 타입 변경이 repository 호출부터 UI 업데이트까지 일관되게 적용되었습니다.Wable-iOS/Domain/RepositoryInterface/ContentRepository.swift (1)
16-19: Repository 인터페이스 통합이 잘 이루어졌습니다!모든 fetch 메서드가 통합된
ContentTemp타입을 반환하도록 변경되어 도메인 모델의 일관성이 향상되었습니다. Combine과 async/await 버전 모두 적절히 업데이트되었습니다.Wable-iOS/Data/Mapper/ContentMapper.swift (3)
13-13: id 파라미터 추가가 적절합니다단일 콘텐츠 fetch 시 응답에서 ID를 가져올 수 없는 경우를 위해 별도 파라미터로 받는 것은 좋은 설계입니다.
32-50: ContentTemp로의 매핑 로직이 일관되게 구현되었습니다!세 가지 toDomain 메서드 모두 새로운
ContentTemp구조로 일관되게 매핑되었습니다. 특히 like 정보가 최상위 레벨 필드(isLiked,likeCount)로 평탄화되어 더 직관적인 구조가 되었습니다.Also applies to: 73-91, 115-133
43-43: isDeleted 필드 매핑 일관성 검토 필요ContentMapper.swift에서
isDeleted를 다음과 같이 다르게 처리하고 있습니다:
- 라인 43 (FetchContent 매핑):
isDeleted: nil— DTO.Response.FetchContent에는isDeleted필드가 존재- 라인 84 (FetchContents 매핑):
isDeleted: content.isDeleted— DTO.Response.FetchContents의isDeleted값을 그대로 사용- 라인 126 (FetchUserContents 매핑):
isDeleted: nil— DTO.Response.FetchUserContents에는isDeleted필드가 없음위 차이가 의도된 동작인지, DTO 계층과 도메인 매핑에서 삭제 상태를 올바르게 반영하고 있는지 확인 부탁드립니다.
Wable-iOS/Presentation/Profile/Other/ViewModel/OtherProfileViewModel.swift (2)
78-78: 현재 구현이 정확합니다
ContentTemp의isLiked프로퍼티 접근이 올바르게 구현되어 있습니다.
227-230: ContentTemp 타입 마이그레이션 확인됨
fetchUserContentList가 올바르게[ContentTemp]를 반환하도록 업데이트되었고, 타입 선언이 일관되게 적용되었습니다.Wable-iOS/Presentation/Home/ViewModel/HomeDetailViewModel.swift (2)
80-80: ContentTemp로의 타입 마이그레이션 완료Output 구조체의
content퍼블리셔와 내부contentSubject가 모두ContentTemp?타입으로 올바르게 업데이트되었습니다.Also applies to: 92-92
189-202: ContentTemp 생성자 호출 인수 순서 일치 확인
ContentTemp의 선언된 멤버 순서(id, author, text, title, imageURL, isDeleted, createdDate, isLiked, likeCount, opacity, commentCount, status)와 비교한 결과, 생성자 호출이 정확히 일치합니다. 수정이 필요 없습니다.Wable-iOS/Presentation/Home/ViewModel/HomeViewModel.swift (2)
60-61: ContentTemp 타입 마이그레이션 성공적으로 완료Public API가 올바르게
ContentTemp로 업데이트되었고, 내부 subject도 일관되게 변경되었습니다.Also applies to: 68-68
135-135: 페이지네이션 커서 업데이트 확인
lastItem.id를 커서로 사용하도록 올바르게 변경되었습니다. ContentTemp의 id 필드가 페이지네이션에 적합한지 확인이 필요합니다.Wable-iOS/Data/RepositoryImpl/ContentRepositoryImpl.swift (2)
57-64: ContentMapper.toDomain 호출 시그니처 변경 확인
ContentMapper.toDomain($0, contentID)호출이 두 개의 파라미터를 받도록 변경되었습니다. 매퍼의 구현이 이를 올바르게 처리하는지 확인됨.
75-82: fetchUserContentList 메서드 일관성 확인Publisher와 async 버전 모두
[ContentTemp]를 반환하도록 올바르게 업데이트되었고, 에러 매핑도 적절히 처리되었습니다.Also applies to: 84-94
Wable-iOS/Presentation/Home/View/HomeDetailViewController.swift (3)
25-26: ContentTemp로의 타입 마이그레이션 완료Item enum과 cell registration이 올바르게 ContentTemp를 사용하도록 업데이트되었습니다.
Also applies to: 205-206
217-218: authorType 계산 로직 간소화됨
item.author.id를 직접 사용하여 코드가 더 간결해졌습니다.
775-782: updateContent 메서드 시그니처 업데이트 확인메서드가 올바르게
ContentTemp타입을 받도록 업데이트되었습니다.
Wable-iOS/Domain/UseCase/Profile/FetchUserContentListUseCase.swift
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
Wable-iOS/Domain/Entity/Comment.swift (1)
41-55: children가 구 모델(ContentComment)을 참조합니다 — [CommentTemp]로 통일하고 식별/해시 가능하도록 보강 권장통합 목표(Temp 기반 단일 모델)와 상충합니다. 트리 구조에서 타입 혼재는 매핑/표현 계층 복잡도와 상태 불일치 리스크를 키웁니다. 또한 SwiftUI/콜렉션 디프/세트 사용을 고려하면 Identifiable/Hashable 채택이 필요합니다. 아래처럼 정리해 주세요.
-struct CommentTemp: Likable { +struct CommentTemp: Identifiable, Hashable, Likable { let author: User let text: String let commentID: Int let contentID: Int let isDeleted: Bool? let createdDate: Date? let parentContentID: Int? - let children: [ContentComment]? + let children: [CommentTemp]? var likeCount: Int var isLiked: Bool var opacity: Opacity var status: PostStatus + var id: Int { commentID } }추가로, 전역 코드에서 ContentComment 기반 children 접근을 사용하는 곳이 있다면 함께 치환이 필요합니다. 원하시면 전역 리팩터링 패치 제안 가능합니다.
🧹 Nitpick comments (3)
Wable-iOS/Domain/Entity/Comment.swift (3)
49-49: 옵셔널 children 대신 빈 배열이 호출부를 단순화합니다nil 체크를 줄이고 forEach/collection 디프 사용성을 높이기 위해 기본값이 빈 배열인 비옵셔널을 권장합니다.
- let children: [CommentTemp]? + let children: [CommentTemp]
46-46: isDeleted는 Bool(비옵셔널) 일관화를 권장동일 파일 내 ContentComment는 Bool을 사용합니다(라인 35). 도메인 의미가 “삭제 여부”라면 비옵셔널 Bool이 적합합니다. 매퍼에서 기본값(false) 보장 혹은 명시적 세팅을 권장합니다.
- let isDeleted: Bool? + let isDeleted: Bool
48-48: CommentTemp의parentContentID네이밍 수정 제안
parentContentID는 실제로 “부모 댓글 ID”를 나타내므로,parentCommentID(또는 도메인ContentComment와 통일하려면parentID)로 변경하는 것이 명확합니다.– 변경 대상:
• 파일:Wable-iOS/Domain/Entity/Comment.swift
• 구조체:CommentTemp
• 프로퍼티:parentContentID: Int?→parentCommentID: Int?
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
Wable-iOS/Domain/Entity/Comment.swift(2 hunks)
🔇 Additional comments (1)
Wable-iOS/Domain/Entity/Comment.swift (1)
39-39: 섹션 마킹 추가는 가독성에 도움 됩니다임시 모델 블록을 명확히 구분해 주어 탐색성이 좋아졌습니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
Wable-iOS/Presentation/Home/View/HomeDetailViewController.swift (1)
216-352: 셀 내부 핸들러 클로저에서 self 강참조 → 순환 참조/메모리 릭 위험cell.configureCell에 전달되는 각 핸들러(이미지 탭, 좋아요, 설정, 프로필, 고스트) 및 버튼 UIAction이 self를 강하게 캡처합니다. 셀/버튼이 클로저를 강하게 보관하면 VC ↔︎ 컬렉션뷰/셀 ↔︎ 클로저 ↔︎ VC 순환 참조가 발생할 수 있습니다. 각 핸들러에 [weak self] 캡처 리스트를 추가하고 초기에 guard로 self를 확보하는 패턴을 권장합니다. (commentCellRegistration 쪽 핸들러들도 동일한 패턴 적용을 권장)
아래는 핵심 시작 부분만 발췌한 패치 예시입니다.
- contentImageViewTapHandler: { + contentImageViewTapHandler: { [weak self] in + guard let self = self else { return } guard let image = cell.contentImageView.image else { return } let photoDetailViewController = PhotoDetailViewController(image: image) self.navigationController?.pushViewController(photoDetailViewController, animated: true) }, - likeButtonTapHandler: { + likeButtonTapHandler: { [weak self] in + guard let self = self else { return } AmplitudeManager.shared.trackEvent(tag: .clickLikeComment) self.didContentHeartTappedSubject.send(cell.likeButton.isLiked) }, - settingButtonTapHandler: { + settingButtonTapHandler: { [weak self] in + guard let self = self else { return } let viewController = WableBottomSheetController() ... }, - profileImageViewTapHandler: { - if self.activeUserID == item.author.id, + profileImageViewTapHandler: { [weak self] in + guard let self = self else { return } + if self.activeUserID == item.author.id, let tabBarController = self.tabBarController { tabBarController.selectedIndex = 4 } else { let viewController = OtherProfileViewController( viewModel: .init( userID: item.author.id, ... )) self.navigationController?.pushViewController(viewController, animated: true) } }, - ghostButtonTapHandler: { + ghostButtonTapHandler: { [weak self] in + guard let self = self else { return } AmplitudeManager.shared.trackEvent(tag: .clickGhostPost) self.showGhostSheet(onCancel: { AmplitudeManager.shared.trackEvent(tag: .clickWithdrawghostPopup) }, onPrimary: { message in AmplitudeManager.shared.trackEvent(tag: .clickApplyghostPopup) self.didGhostTappedSubject.send((item.id, item.author.id, message, .content)) }) } ) - cell.commentButton.addAction(UIAction(handler: { _ in + cell.commentButton.addAction(UIAction(handler: { [weak self] _ in + guard let self = self else { return } AmplitudeManager.shared.trackEvent(tag: .clickWriteComment) self.createCommentButton.isEnabled = false self.didCommentTappedSubject.send() self.commentTextView.text = "" self.updatePlaceholder(for: item.author.nickname, type: .ripple) self.commentTextView.endEditing(true) DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { self.commentTextView.becomeFirstResponder() } }), for: .touchUpInside)commentCellRegistration의 like/setting/profile/ghost/reply 핸들러들도 같은 방식으로 [weak self] 적용을 권장합니다.
🧹 Nitpick comments (2)
Wable-iOS/Presentation/Home/View/HomeDetailViewController.swift (2)
205-219: 셀 등록/바인딩의 ContentTemp 적용은 적절합니다 (경미한 가독성 제안 포함)ContentCollectionViewCell 등록 제네릭과 configure 파라미터를 ContentTemp로 정리한 부분은 좋습니다. authorType 계산식은 Optional 비교를 명시적으로 표기하면 가독성이 조금 더 좋아집니다.
아래처럼 괄호로 의도를 드러내는 정도의 미세 수정 제안입니다.
- authorType: item.author.id == self.activeUserID ? .mine : .others, + authorType: (self.activeUserID == item.author.id) ? .mine : .others,
583-601: ContentTemp 재생성 로직 단순화 + isDeleted 전달 여부 확인현재 output.content에서 받은 content로 다시 ContentTemp를 구성하면서 isDeleted를 고정 false로 설정합니다. 원본의 삭제 상태를 UI에 반영해야 한다면, 이 값은 소스의 값을 전달해야 합니다. 또한 output.content가 이미 ContentTemp 타입이라면 굳이 재생성하지 않고 그대로 전달하는 편이 간결합니다.
옵션 A: output.content가 이미 ContentTemp인 경우 단순 통과
- owner.updateContent( - ContentTemp( - id: content.id, - author: content.author, - text: content.text, - title: content.title, - imageURL: content.imageURL, - isDeleted: false, - createdDate: content.createdDate, - isLiked: content.isLiked, - likeCount: content.likeCount, - opacity: content.opacity, - commentCount: content.commentCount, - status: content.status - ) - ) + owner.updateContent(content)옵션 B: 재생성이 필요하다면 isDeleted 전달 보정
- isDeleted: false, + isDeleted: content.isDeleted,참고: 이전 커밋에서 지적된 id 설정 이슈(activeUserID 사용)는 본 변경에서 content.id로 교정되어 적절합니다. 굿.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
Wable-iOS/Domain/UseCase/Profile/FetchUserContentListUseCase.swift(1 hunks)Wable-iOS/Presentation/Home/View/HomeDetailViewController.swift(13 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- Wable-iOS/Domain/UseCase/Profile/FetchUserContentListUseCase.swift
🔇 Additional comments (2)
Wable-iOS/Presentation/Home/View/HomeDetailViewController.swift (2)
771-778: Diffable Snapshot 업데이트 로직은 간결하고 올바릅니다콘텐츠 섹션 아이템을 전체 교체하는 방식이 UI 동기화 관점에서 명확합니다. 애니메이션 사용도 적절합니다.
25-27: ContentComment 사용 현황 및 CommentTemp 통합 전략 확인 필요프로젝트 전반에서
ContentComment가 광범위하게 사용되고 있고,CommentTemp는Domain/Entity/Comment.swift에만 정의되어 있습니다.
이 PR의 의도가 단계적 리팩터링인지, 아니면 한 번에CommentTemp로 통합하는 것인지 명확히 해주세요.주요 사용 위치:
- Presentation/Home/View/HomeDetailViewController.swift
case comment(ContentComment)didCommentHeartTappedSubject: PassthroughSubject<(Bool, ContentComment), Never>- 콜렉션뷰 셀 등록 및
updateComments(_ comments: [ContentComment])- Presentation/Home/ViewModel/HomeDetailViewModel.swift
AnyPublisher<(Bool, ContentComment), Never>AnyPublisher<[ContentComment], Never>및 내부 매핑 로직 다수- Data/RepositoryImpl/CommentRepositoryImpl.swift
fetchContentCommentList반환 타입- Data/Mapper/CommentMapper.swift
toDomain(_:)에서ContentComment생성- Domain/Entity/Comment.swift
struct ContentComment,struct CommentTemp정의만약 이 PR에서 댓글 타입을
CommentTemp로 한꺼번에 통합할 계획이라면, 위 위치들의 타입을 모두 교체해야 합니다.
단계적 전환이라면 PR 설명이나 코드 주석에 의도를 명시해 주세요.
JinUng41
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CommentTemp에 대해서는 아직 수정을 안하신거겠죠?
고생많으셨습니다.
많은 부분 헷갈리셨을수도 있는데 잘 해내신 것 같아요.
감사합니다!!
| let isDeleted: Bool? | ||
| let createdDate: Date? | ||
| let parentContentID: Int? | ||
| let children: [ContentComment]? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
자식 댓글을 사용하지 않는 곳에서는 빈 배열로 관리해도 괜찮지 않을까 생각했는데, 어떠세요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오....... 옵셔널 바인딩을 하지 않아도 돼서 조금 더 편할 것 같습니다. 반영해볼게요!!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (1)
Wable-iOS/Domain/Entity/Comment.swift (1)
41-55: children에 구 모델이 혼재되어 트리 일관성이 깨집니다 — CommentTemp로 통일 및 Identifiable/Hashable 채택 권장현재 CommentTemp.children이 [ContentComment]로 선언되어 있어 새 모델과 구 모델이 섞입니다. 트리 순회/매핑 시 타입 변환 오버헤드와 상태 불일치가 발생할 수 있어 본 PR 목적(통합)과 상충합니다. 또한 UI/컬렉션에서 안정적인 식별/해싱을 위해 Identifiable/Hashable 채택을 권장합니다. id는 commentID로 노출하면 됩니다. children은 과거 논의대로 non-optional로 두되 기본값 빈 배열을 제공하면 옵셔널 바인딩 제거 효과를 유지할 수 있습니다.
아래처럼 반영을 제안합니다:
-struct CommentTemp: Likable { +struct CommentTemp: Identifiable, Hashable, Likable { let author: User let text: String let commentID: Int let contentID: Int let isDeleted: Bool? let createdDate: Date? let parentContentID: Int? - let children: [ContentComment] + let children: [CommentTemp] = [] var likeCount: Int var isLiked: Bool var opacity: Opacity var status: PostStatus + + var id: Int { commentID } }추가 메모:
- 구 모델 ContentComment의 childs 네이밍과도 불일치(children vs childs)가 있어, 전역적으로 children으로 통일하면 검색/리팩터링 생산성이 올라갑니다.
🧹 Nitpick comments (2)
Wable-iOS/Domain/Entity/Comment.swift (2)
41-55: isDeleted 옵셔널 제거 및 기본값 false 권장삭제 여부는 도메인상 3상태가 필요하지 않다면 Bool? 대신 Bool로 단순화하는 편이 안전하고 사용처에서의 불필요한 옵셔널 처리도 줄어듭니다. 서버 스키마가 비어 있을 수 있다면 매퍼에서 기본값 false를 주입하면 됩니다.
- let isDeleted: Bool? + let isDeleted: Bool = false
41-55: 대댓글 동적 추가/삭제 플로우가 있다면 children을 var로 전환 고려현재 children이 let이라 런타임에 대댓글을 추가하려면 전체 모델을 재생성해야 합니다. 이미 likeCount/isLiked는 var로 뮤터블하게 관리 중이라 일관성을 위해 children도 var로 두는 선택지가 있습니다. 반대로 완전 불변 모델을 지향한다면 like 관련 상태도 외부 스토어로 분리하는 쪽이 더 깔끔합니다.
- let children: [CommentTemp] = [] + var children: [CommentTemp] = []
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
Wable-iOS/Domain/Entity/Comment.swift(2 hunks)
🔇 Additional comments (1)
Wable-iOS/Domain/Entity/Comment.swift (1)
2-2: 파일 리네임/헤더 변경 문제 없습니다파일명 갱신에 따른 헤더 변경으로 보이며, 별도 이슈 없어 보입니다.
| struct CommentTemp: Likable { | ||
| let author: User | ||
| let text: String | ||
| let commentID: Int | ||
| let contentID: Int | ||
| let isDeleted: Bool? | ||
| let createdDate: Date? | ||
| let parentContentID: Int? | ||
| let children: [ContentComment] | ||
|
|
||
| var likeCount: Int | ||
| var isLiked: Bool | ||
| var opacity: Opacity | ||
| var status: PostStatus | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
parentContentID의 의미 확인 필요 — 부모 ‘댓글’ ID인지 ‘게시물’ ID인지 검증 요청
필드명이 parentContentID라 상위 게시물 ID로 읽히지만, 대댓글 트리를 다룬다면 부모 댓글 ID(parentCommentID)가 필요할 수 있습니다. 의도된 스키마인지 확인 부탁드립니다. 만약 부모 댓글 ID라면 네이밍을 parentCommentID(또는 parentID)로 바꾸는 것이 정확합니다.
아래 스크립트로 레포 내 사용처를 훑어보면 혼용 여부를 빠르게 확인할 수 있습니다.
🏁 Script executed:
#!/bin/bash
# parentContentID / parentCommentID 사용처와 문맥 확인
set -euo pipefail
echo "== References to parentContentID =="
rg -n -C3 --glob '!**/Pods/**' --glob '!**/DerivedData/**' '\bparentContentID\b'
echo
echo "== References to parentCommentID =="
rg -n -C3 --glob '!**/Pods/**' --glob '!**/DerivedData/**' '\bparentCommentID\b|\bparentID\b'Length of output: 17163
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== References to CommentTemp =="
rg -n -C3 --glob '!**/Pods/**' '\bCommentTemp\b'Length of output: 549
CommentTemp의 parentContentID 네이밍 일관성 검토 및 수정 요망
CommentTemp의 parentContentID가 실제로는 부모 댓글의 ID를 나타내는 것으로 보입니다. 도메인 모델(ContentComment)에서는 동일한 의미로 parentID를 사용하고 있으므로, 혼동을 줄이고 일관성을 유지하기 위해 아래와 같이 네이밍을 변경해 주세요.
-
변경 위치
• Wable-iOS/Domain/Entity/Comment.swift — struct CommentTemp -
수정 제안
- let parentContentID: Int? + let parentID: Int? // 또는 + let parentCommentID: Int?
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In Wable-iOS/Domain/Entity/Comment.swift around lines 41 to 55, the property
parentContentID on struct CommentTemp represents the parent comment ID but is
named inconsistently with ContentComment which uses parentID; rename
parentContentID to parentID (keeping the same type and optionality), update all
local references/usages, initializers, Codable/Decodable keys (or CodingKeys)
and any mapping/conversion code to use parentID, and run/adjust any callers or
tests to reflect the new name to maintain behavior and compile cleanly.
[Refactor] 파편화된 Content, Comment 엔티티 통합 및 홈, 상세, 프로필 화면에 적용 (Content)
👻 PULL REQUEST
📄 작업 내용
ContentTemp,CommentTemp(임시 네이밍)로 통합했어요.Likable프로토콜을 통해 구현하고,ContentTemp,CommentTemp가 각각Likable프로토콜을 따르도록 리팩토링했어요.ContentTemp,CommentTemp로 변환했어요.💻 주요 코드 설명
파편화된 Content 관련 엔티티 통합
Content,UserContent,ContentInfo로 게시물 엔티티가 파편화되어 있었습니다.Content,UserContent,ContentInfo를 단일 엔티티인ContentTemp로 통합하고 관리함으로써 데이터 변환 로직을 단순화하고, 확장성과 유지보수성을 높였습니다.효율적인 좋아요 상태 관리를 위한
Likable프로토콜 도입ContentTemp,CommentTemp는 모두 좋아요 기능을 가지고 있습니다.isLiked,likedCount프로퍼티를 가져 상태를 관리할 수 있어야 합니다.Likable이라는 프로토콜을 통해 관리하고 프로토콜 익스텐션 내 mutating function을 통해 좋아요, 좋아요 취소 기능을 구현함으로써 보일러 플레이트 코드를 제거하고, 기능 확장성을 높였습니다.👀 리뷰어에게 전달할 사항
✅ 이번 PR에서 이런 부분을 중점적으로 체크해주세요!
🔗 연결된 이슈
Summary by CodeRabbit