- 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)inswitch networkResult{case.success(let data):print(self.isFromFollowingTab)ifself.isFromFollowingTab {self.followScrapButtonDelegate?.fromAnswerVC(indexInVC:self.indexInFollowingVC!)}case.requestErr(let msg):iflet message = msg as?String{print(message)}case.pathErr :print("pathErr")case.serverErr :print("serverErr")case.networkFail:print("networkFail")}}- 타인이 쓴 글 보기
다른 페이지를 다녀와서 다른 사람의 글에 변동이 생길 경우 새로 통신을 해서 Reload해줘야함 페이징 해서 정보를 받기 때문에 1페이지부터 원래의 페이지까지 다시 받아와야 함 이 과정에서 처음에는 for문을 이용해서 어려움을 겪었으나, 통신에서의 재귀함수 호출을 통해 해결
func getUpdateAnswers(){letloadingFrame=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 +=1letloadingFrame=CGRect(x:0, y:0, width: view.frame.width, height: view.frame.height)FollowingGetAnswersService.shared.getAnswerData(page: curPage){(networkResult)->(Void)inswitch networkResult{case.success(let data):iflet answerDatas = data as?FollowingAnswersData{self.pageLen = answerDatas.pageLen
foranswerDatain answerDatas.answers{self.answers.append(answerData)}}ifself.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()ifself.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):iflet message = msg as?String{print(message)}case.pathErr :print("pathErr")case.serverErr :print("serverErr")case.networkFail:print("networkFail")}}}UIView Extension
extensionUIView{ // Set Rounded View func makeRounded(cornerRadius :CGFloat?){ // UIView 의 모서리가 둥근 정도를 설정 iflet 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 의 테두리 색상 설정 iflet 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 의 테두리 두께 설정 iflet borderWidth_ = borderWidth {self.layer.borderWidth = borderWidth_ }else{ // borderWidth 변수가 nil 일 경우의 default self.layer.borderWidth =1.0}}}
UIViewController
extensionUIViewController{ // 토스트 메세지 func showToast(text:String, completion:@escaping()->()){lettoast=ToastView(frame:CGRect(x:0, y:0, width:343, height:84)) toast.setLabel(text: text) toast.alpha =0self.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 inUIView.animate(withDuration:0.3, delay:0.7, animations:{ toast.alpha =0}, completion:{ finish inif finish { toast.removeFromSuperview()completion()}})})}}
UIImageView
// Kingfisher를 이용하여 url로부터 이미지를 가져오는 extension extensionUIImageView{publicfunc imageFromUrl(_ urlString:String?){iflet url = urlString {self.kf.setImage(with:URL(string: url), options:[.transition(ImageTransition.fade(0.5))])}}}
| 윤재 | 세란 | 재용 |
|---|---|---|
![]() | ![]() | |
| 네이스 |




