- SOPT 27th 장기 해커톤 APPJAM
- 기간: 2020.12.26 ~ 2021.1.16
매일 질문에 답을 하며 나를 알아가는 질문다이어리 BeMe 입니다.
24시간마다 새로운 질문 제공, 새로운 질문 받기를 통해 질문에 답을 할 수 있습니다. 자신의 글을 전체 공개하여 사람들과 소통할 수 있습니다. 마지막으로 마이페이지에서 내가 지금까지 답한 질문을 쉽게 볼 수 있으며, 내 생각이 어떻게 변했는지 확인할 수 있습니다.
| 라이브러리(Library) | 목적(Purpose) | 버전(VersionA |
|---|---|---|
| Alamofire | 서버 통신 | |
| Kingfisher | 이미지 처리 | |
| SnapKit | 오토레이아웃 | |
| Then | 짧은 코드 처리 | |
| lottie-ios | 로티 애니메이션 처리 | |
| Firebase/Messaging | Firebase Cloud Messaging | |
| SwiftLint | 깔끔한 코딩 컨벤션 |
1. iPhone 12 Pro 적용
2. iPhone 12 mini 적용
3. iPhone SE2 적용
| 화면 | 기능 | 상세 기능 | 개발 |
|---|---|---|---|
| 스플래시 | 윤재🚀 | ||
| 온보딩 | 윤재🚀 | ||
| 회원가입 | 윤재🚀 | ||
| 로그인 | 로그인 | 윤재🚀 | |
| 자동로그인 | 윤재🚀 | ||
| 홈 | 오늘의 질문 및 답변 열람 | 윤재🚀 | |
| 과거의 질문 및 답변 열람 | 윤재🚀 | ||
| 추가 질문 열람 | 윤재🚀 | ||
| 답변 공개 범위 설정 | 윤재🚀 | ||
| 답변 수정 및 삭제 | 윤재🚀 | ||
| 탐색 | 나와 다른 답변들 열람 | 재용🐶 | |
| 다른 답변들 둘러보기 | 최신, 흥미 탭 및 키워드 필터 검색 | 재용🐶 | |
| 스크랩/ 언스크랩 | 재용🐶 | ||
| 신고하기 | 재용🐶 | ||
| 팔로잉 | 팔로잉/ 팔로워의 답변 열람 | 윤재🚀 | |
| 팔로잉/ 팔로워 열람 | 윤재🚀 | ||
| 팔로잉/ 팔로워 검색 | 사용자 검색 | 윤재🚀 | |
| 팔로우/ 언팔로우 | 윤재🚀 | ||
| 팔로워 삭제 | 윤재🚀 | ||
| 신고하기 | 윤재🚀 | ||
| 마이페이지 | 프로필 편집 | 윤재🚀 | |
| 내 글, 스크랩 열람 | 세란🌿 | ||
| 키워드 및 필터 검색 | 세란🌿 | ||
| 답변 공개 범위 설정 | 세란🌿 | ||
| 스크랩/ 언스크랩 | 세란🌿 | ||
| 글 상세 | 답변 | 답변 상세 열람 | 재용🐶 |
| 답변 수정 및 삭제 | 재용🐶 | ||
| 스크랩/언스크랩 | 재용🐶 | ||
| 신고하기 | 재용🐶 | ||
| 댓글 | 댓글 작성 | 재용🐶 | |
| 댓글의 답글 작성 | 재용🐶 | ||
| 댓글 공개범위 설정 | 재용🐶 | ||
| 댓글 수정 및 삭제 | 재용🐶 | ||
| 글 쓰기 | 공개범위 및 댓글 기능 설정 | 윤재🚀, 세란🌿 | |
| 임시저장 | 세란🌿 | ||
| 답변하기 | 세란🌿 | ||
| 타인페이지 | 팔로우/ 언팔로우 | 세란🌿 | |
| 스크랩/ 언스크랩 | 세란🌿 | ||
| 신고하기 | 세란🌿 | ||
| 최근 활동 | 댓글 및 답글 알림 | ||
| 팔로워 알림 | |||
| 장기 푸쉬 알림 | 오늘의 질문 받기 | 윤재🚀 |
- 글쓰기
answer data를 넣어서 글을 등록하는 코드
AnswerRegistService.shared.regist(answerID: answerData!.id!, content: answerData!.answer!, commentBlocked: commentSwitch.isOn, isPublic: answerSwitch.isOn) {(networkResult) -> (Void) in
switch networkResult{
case .success(let data) :
print(self.isFromFollowingTab)
if self.isFromFollowingTab {
self.followScrapButtonDelegate?.fromAnswerVC(indexInVC: self.indexInFollowingVC!)
}
case .requestErr(let msg):
if let message = msg as? String {
print(message)
}
case .pathErr :
print("pathErr")
case .serverErr :
print("serverErr")
case .networkFail:
print("networkFail")
}
}- 타인이 쓴 글 보기
다른 페이지를 다녀와서 다른 사람의 글에 변동이 생길 경우 새로 통신을 해서 Reload해줘야함 페이징 해서 정보를 받기 때문에 1페이지부터 원래의 페이지까지 다시 받아와야 함 이 과정에서 처음에는 for문을 이용해서 어려움을 겪었으나, 통신에서의 재귀함수 호출을 통해 해결
func getUpdateAnswers(){
let loadingFrame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height)
LoadingHUD.show(loadingFrame: loadingFrame,color: .white)
curPage = 0
answers = []
updateDataOnePage()
}
func updateDataOnePage(){
curPage += 1
let loadingFrame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height)
FollowingGetAnswersService.shared.getAnswerData(page: curPage){(networkResult) -> (Void) in
switch networkResult{
case .success(let data) :
if let answerDatas = data as? FollowingAnswersData {
self.pageLen = answerDatas.pageLen
for answerData in answerDatas.answers{
self.answers.append(answerData)
}
}
if self.curPage < self.answerPage {
self.updateDataOnePage()
}
else{
DispatchQueue.global(qos: .background).sync {
self.wholeCollectionView.reloadData()
self.wholeCollectionView.setContentOffset(CGPoint(x: 0, y: self.lastY), animated: false)
}
LoadingHUD.hide()
if self.answers.count == 0{
self.customEmptyView.setItems(text: "아이쿠..! 아직 팔로우하는 사람이 없군요\n팔로잉을 하고 다른 사람들의 글을 둘러보세요")
self.wholeCollectionView.addSubview(self.customEmptyView)
print(self.customEmptyView.superview?.bounds.minX)
self.customEmptyView.snp.makeConstraints{
$0.centerX.equalToSuperview()
$0.top.equalToSuperview().offset(362)
$0.height.equalTo(80)
}
}
else{
self.customEmptyView.removeFromSuperview()
}
}
print("success")
case .requestErr(let msg):
if let message = msg as? String {
print(message)
}
case .pathErr :
print("pathErr")
case .serverErr :
print("serverErr")
case .networkFail:
print("networkFail")
}
}
}
-
UIView Extension
extension UIView { // Set Rounded View func makeRounded(cornerRadius : CGFloat?){ // UIView 의 모서리가 둥근 정도를 설정 if let cornerRadius_ = cornerRadius { self.layer.cornerRadius = cornerRadius_ } else { // cornerRadius 가 nil 일 경우의 default self.layer.cornerRadius = self.layer.frame.height / 2 } self.layer.masksToBounds = true } // Set UIView's Shadow func dropShadow(color: UIColor, offSet: CGSize, opacity: Float, radius: CGFloat) { // 그림자 색상 설정 layer.shadowColor = color.cgColor // 그림자 크기 설정 layer.shadowOffset = offSet // 그림자 투명도 설정 layer.shadowOpacity = opacity // 그림자의 blur 설정 layer.shadowRadius = radius // 구글링 해보세요! layer.masksToBounds = false } // Set UIView's Border func setBorder(borderColor : UIColor?, borderWidth : CGFloat?) { // UIView 의 테두리 색상 설정 if let borderColor_ = borderColor { self.layer.borderColor = borderColor_.cgColor } else { // borderColor 변수가 nil 일 경우의 default self.layer.borderColor = UIColor(red: 205/255, green: 209/255, blue: 208/255, alpha: 1.0).cgColor } // UIView 의 테두리 두께 설정 if let borderWidth_ = borderWidth { self.layer.borderWidth = borderWidth_ } else { // borderWidth 변수가 nil 일 경우의 default self.layer.borderWidth = 1.0 } } }
-
UIViewController
extension UIViewController { // 토스트 메세지 func showToast(text: String, completion: @escaping ()->()) { let toast = ToastView(frame: CGRect(x: 0, y: 0, width: 343, height: 84)) toast.setLabel(text: text) toast.alpha = 0 self.view.addSubview(toast) toast.snp.makeConstraints { $0.leading.equalToSuperview().offset(16) $0.trailing.equalToSuperview().offset(-16) $0.bottom.equalToSuperview().offset(-101) } UIView.animate(withDuration: 0.3, animations: { toast.alpha = 1 },completion: { finish in UIView.animate(withDuration: 0.3, delay: 0.7, animations: { toast.alpha = 0 }, completion: { finish in if finish { toast.removeFromSuperview() completion() } }) }) } }
-
UIImageView
// Kingfisher를 이용하여 url로부터 이미지를 가져오는 extension extension UIImageView { public func imageFromUrl(_ urlString: String?) { if let url = urlString { self.kf.setImage(with: URL(string: url), options: [.transition(ImageTransition.fade(0.5))]) } } }
| 윤재 | 세란 | 재용 |
|---|---|---|
![]() |
![]() |
|
| 네이스 |




