소셜 관련 앱을 사용하면 다른 사람의 프로필을 누르면 해당 사용자의 프로필을 볼 수 있는 페이지로 넘어가는 것이 일반적인 경우이다. 이 기능을 이번에 구현해보고자 한다.
이 기능의 흐름은 다음과 같다.
1. 제스처 인식(GestureRecognizer) : imageView에서 탭을 감지
2. 콜백 함수(Callback Function) : 클릭이 감지될 때 호출되는 함수
3. 클로저(Closure) : imageView를 포함하는 ViewController에게 알려주어 화면 전환을 처리할 수 있게 함
var onImageTap: (() -> Void)?
private func addTapGestureToProfileImageView() {
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(profileImageTapped))
profileImageView.isUserInteractionEnabled = true
profileImageView.addGestureRecognizer(tapGesture)
}
@objc private func profileImageTapped() {
onImageTap?()
}
이미지가 탭 될때마다 클로저가 호출되도록 한다.
UITapGestureRecognizer
는 제스처 인식기의 한 종류로, 사용자가 화면의 특정 부분을 탭할 때, 이를 감지하는 역할을 한다.
간단한 탭 감지: UITapGestureRecognizer는 한 번 또는 여러 번 연속해서 화면을 탭하는 제스처를 감지할 수 있다.
커스터마이즈 가능: 탭의 횟수(예: 더블 탭), 손가락의 수 등을 설정하여 감지되는 제스처의 종류를 세밀하게 조정할 수 있다.
UIView에 추가: UITapGestureRecognizer는 UIView의 인스턴스에 추가될 수 있으며, 이 뷰 내에서 발생하는 탭 제스처를 감지한다.
타겟-액션 메커니즘: 탭이 감지되었을 때 실행할 메소드를 지정할 수 있다. 이는 타겟(대상 객체)과 액션(실행할 메소드)을 지정하여 설정한다.
다른 제스처 인식기와의 상호작용: 여러 제스처 인식기가 동일한 뷰에 추가되었을 때, 서로 영향을 주고받을 수 있다. 예를 들어, UITapGestureRecognizer와 UIPanGestureRecognizer를 동시에 사용할 때, 둘 사이의 우선순위를 설정할 수 있다.
https://developer.apple.com/documentation/uikit/uitapgesturerecognizer
해당 imageView를 포함하는 ViewController에서 onImageTap 클로저를 설정한다. 현재는 해당 유저의 정보를 불러와서 Profile 화면에 보여주는 코드를 넣어주면 된다. 이 코드는 다양한 화면에서 사용하기 때문에 class로 따로 만들었다.
class PresentToProfileVC {
static let urlCache = FBURLCache.shared
static let storage = Storage.storage().reference()
static func presentToProfileVC(from presentingVC: UIViewController, with profile: UserSummary) {
let profileViewController = MyProfileViewController()
profileViewController.userProfile = profile
// 이미지 로딩 로직
if let profileImageURL = profile.profileImagePath {
self.getUserImage(referencePath: profileImageURL, imageSize: .medium) { [weak profileViewController] downloadedImage in
DispatchQueue.main.async {
if let image = downloadedImage {
profileViewController?.profileImage.setImage(image, for: .normal)
}
}
}
} else {
let defaultImage = UIImage(named: "profile") ?? UIImage(systemName: "person.fill")
profileViewController.profileImage.setImage(defaultImage, for: .normal)
}
profileViewController.profileName.text = profile.nickName
profileViewController.choiceEnjoyTextField.text = profile.hobbyList?.first
profileViewController.selfInfoDetail.text = profile.description
profileViewController.profileImage.isUserInteractionEnabled = true
profileViewController.profileName.isEditable = false
profileViewController.choicePickerView.isUserInteractionEnabled = false
profileViewController.selfInfoDetail.isEditable = false
profileViewController.logout.isHidden = true
profileViewController.line.isHidden = true
profileViewController.deleteID.isHidden = true
presentingVC.present(profileViewController, animated: true, completion: nil)
}
static func getUserImage(referencePath: String?, imageSize: ImageSize, completion: @escaping(UIImage?) -> Void) {
guard let referencePath = referencePath else { return }
let imageRefPath = storage.child(referencePath).child(imageSize.rawValue).fullPath
self.urlCache.downloadURL(storagePath: imageRefPath) { result in
switch result {
case .success(let image):
completion(image)
case .failure(let error):
print(error.localizedDescription)
}
}
}
}
MyProfileViewController는 이미 만들어둔 상태에서 재사용하고 있고, UserSummary라는 구조체로 사용자의 데이터를 저장하고 있다.
이렇게 만든 함수들을 클로저 안에 넣어주면 된다.
func navigateToProfilePage(for indexPath: IndexPath) {
if let userList = firebaseClubDatabaseManager.model?.userList {
let profile = userList[indexPath.row]
PresentToProfileVC.presentToProfileVC(from: self, with: profile)
}
}