Skip to content

three523/IDo

ย 
ย 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation


๐Ÿ‘๐ŸปiDo

์ทจ๋ฏธ ๊ณต์œ ๋ฅผ ์œ„ํ•œ ์ปค๋ฎค๋‹ˆํ‹ฐ ์•ฑ


๋ชฉ์ฐจ


๐Ÿ“† ํ”„๋กœ์ ํŠธ ๊ธฐ๊ฐ„

2023๋…„ 10์›” 10์ผ ~ 2023๋…„ 11์›” 17์ผ (6์ฃผ)


โญ๏ธ ํ”„๋กœ์ ํŠธ ์†Œ๊ฐœ

ํ”„๋กœ์ ํŠธ ๋ชฉํ‘œ

์•ฑ ๋ฐฐํฌ, ํŒŒ์ด์–ด๋ฒ ์ด์Šค ์—ฐ๋™, ์ด๋ฏธ์ง€ ๋‹ค๋ฃจ๊ธฐ


๐Ÿ“š ๋‚˜์˜ ๊ตฌํ˜„ ๊ธฐ๋Šฅ

  1. ๊ณตํ†ต

    • ์ด๋ฏธ์ง€ ์บ์‹ฑ ์ž‘์—…
    • ์ด๋ฏธ์ง€ ๋ฆฌ์‚ฌ์ด์ง• ์ž‘์—…
    • ํŽ˜์–ด ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋„์ž…

  2. ํ™ˆ ํŽ˜์ด์ง€

    • ๊ฐ€์ž…ํ•œ ๋ชจ์ž„ ๋ชฉ๋ก ํ‘œ์‹œ

  3. ๋ชจ์ž„ ํŽ˜์ด์ง€

    • ๊ฐ€์ž… ๋ฉค๋ฒ„ ๋ชฉ๋ก
    • ๋ชจ์ž„์žฅ ํ‘œ์‹œ

  4. ๊ฒŒ์‹œ๊ธ€ ํŽ˜์ด์ง€

    • ์ œ๋ชฉ, ๋‚ด์šฉ, ์ด๋ฏธ์ง€, ์ž‘์„ฑ ์‹œ๊ฐ„ ํ‘œ์‹œ
    • ๊ฒŒ์‹œ๊ธ€ ์ถ”๊ฐ€/์‚ญ์ œ/์ˆ˜์ • ๊ธฐ๋Šฅ
    • ๋Œ“๊ธ€ ์ถ”๊ฐ€/์‚ญ์ œ/์ˆ˜์ • ๊ธฐ๋Šฅ
    • ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ํด๋ฆญ ์‹œ, ํ•ด๋‹น ์œ ์ € ํ”„๋กœํ•„ ํ™•์ธ
    • ๊ฒŒ์‹œ๊ธ€ ์‹ ๊ณ ํ•˜๊ธฐ
    • ๋Œ“๊ธ€ ์‹ ๊ณ ํ•˜๊ธฐ


๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป Contributors

ํ™์ค€์˜ ๊น€๋„ํ˜„ ๊ฐ•์ง€ํ›ˆ ํ•œ๋™์—ฐ ์ด์• ๋ผ
โ˜€๏ธ ๋ฆฌ๋” ๏ธ๐ŸŒ™ ๋ถ€๋ฆฌ๋” ๐Ÿ› ๏ธ ๊ฐœ๋ฐœ์ž ๐Ÿ› ๏ธ ๊ฐœ๋ฐœ์ž ๐Ÿ› ๏ธ ๊ฐœ๋ฐœ์ž
๊ฒŒ์‹œ๊ธ€ ๋ชฉ๋ก/๊ฒŒ์‹œ๊ธ€ ์ƒ์„ฑ ๋ฐ ์ˆ˜์ • ๊ฒŒ์‹œ๊ธ€ ์ƒ์„ธ/๋Œ“๊ธ€ ํšŒ์›๊ฐ€์ž… ๋ชจ์ž„ ์ƒ์„ฑ/์ˆ˜์ • ํ™ˆ ํ™”๋ฉด
ํšŒ์›ํƒˆํ‡ด ์ด๋ฏธ์ง€ ์บ์‹ฑ ๋กœ๊ทธ์•„์›ƒ ์ด๋ฏธ์ง€ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๊ธฐ๋Šฅ ๋งˆ์ด ํ”„๋กœํ•„ ํ™”๋ฉด
์‹ ๊ณ ๊ธฐ๋Šฅ ์‹ ๊ณ ๊ธฐ๋Šฅ ์นดํ…Œ๊ณ ๋ฆฌ ์ด๋ฏธ์ง€ ํŽธ์ง‘ ์ƒ๋‹จ ๋กœ๊ณ  ์ถ”๊ฐ€

๐Ÿ› ๏ธ Tech Stack



๐Ÿน ์‚ฌ์šฉํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

  1. Firebase
  2. SnapKit
  3. Tabman
  4. TOCropViewController

โ“ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉ ์ด์œ 

  1. Firebase
    ๋กœ๊ทธ์ธ ๋ฐ ํšŒ์›๊ฐ€์ž… ์ง„ํ–‰ ์‹œ ์œ ์ €์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ  ๋น„๊ตํ•˜๊ธฐ ์œ„ํ•ด Authentication์— ๋ฐ์ดํ„ฐ ๋™๊ธฐํ™”๋ฅผ ์œ„ํ•ด์„œ ์‚ฌ์šฉ
    ๋ชจ์ž„/๊ฒŒ์‹œ๊ธ€/๋Œ“๊ธ€ ๋“ฑ ๊ฐ๊ฐ ์ฝ˜ํ…์ธ ์˜ CRUD ๊ธฐ๋Šฅ์„ ์œ„ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ํ™œ์šฉํ•˜๊ธฐ ์œ„ํ•ด Realtime์— ๋ฐ์ดํ„ฐ ๋™๊ธฐํ™”๋ฅผ ์œ„ํ•ด์„œ ์‚ฌ์šฉ
    ์ฝ˜ํ…์ธ , ์œ ์ €์™€ ๊ด€๋ จ๋œ ์ด๋ฏธ์ง€๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ  ์บ์‹ฑํ•˜๊ธฐ ์œ„ํ•ด Storage์— ์ด๋ฏธ์ง€ ์ €์žฅ์„ ์œ„ํ•ด์„œ ์‚ฌ์šฉ

  2. SnapKit
    ์ฝ”๋“œ ๊ธฐ๋ฐ˜ UI ์ž‘์—…์˜ ํšจ์œจ์„ฑ์„ ๋†’์ด๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉ Auto Layout์„ ์‰ฝ๊ฒŒ ์„ค์ •ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ

  3. Tabman
    ์ƒ๋‹จ ํƒญ๋ฐ” ์ถ”๊ฐ€๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉ

  4. TOCropViewController
    ์ด๋ฏธ์ง€ ๋น„์œจ์„ 3:2๋กœ ํŽธ์ง‘์„ ์‰ฝ๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ


๐Ÿ”ซ ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ…

UI ์—…๋ฐ์ดํŠธ

๋ฐ์ดํ„ฐ๊ฐ€ ์ฒ˜๋ฆฌ๋˜๊ธฐ ์ „์—, ํ™”๋ฉด ์ „ํ™˜์ด ๋๋‚˜์„œ ์›ํ•˜๋Š” ๊ฒฐ๊ณผ๊ฐ€ ๋ณด์—ฌ์ง€์ง€ ์•Š์Œ

  • ์›์ธ : ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ๊ฐ€ ์™„๋ฃŒ๋˜๋Š” ์‹œ์ ์„ ์•Œ ์ˆ˜ ์—†์Œ, ์ˆœ์ฐจ์ ์œผ๋กœ ์ง„ํ–‰์ด ๋˜๊ฒŒ ํ•˜๋Š” ๋กœ์ง์ด ์—†์Œ
  • ํ•ด๊ฒฐ : ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜์— completion ์„ ์ถ”๊ฐ€ํ•ด์„œ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ๊ฐ€ ์™„๋ฃŒ๋œ ์‹œ์ ์— ํ™”๋ฉด ์ „ํ™˜์ด ์ด๋ฃจ์–ด์ง€๊ฒŒ ํ•จ
    func createNoticeBoard(title: String, content: String, completion: @escaping (Bool) -> Void) {
        let ref = Database.database().reference().child("noticeBoards").child(club.id)
        let newNoticeBoardID = ref.childByAutoId().key ?? ""
        .
      	  .
      	  .
        self.uploadImages(noticeBoardID: newNoticeBoardID, imageList: self.newSelectedImage) { success, imageURLs in
            if success {
                .
      					  .  
      					  .
                    completion(success)
                }
            } else {
                completion(false)
            }
        }
    }
    // ์‚ฌ์šฉ ์˜ˆ์‹œ
    // ์ƒˆ๋กœ์šด ๋ฉ”๋ชจ ์ž‘์„ฑ
    @objc func finishButtonTappedNew() {
        navigationItem.rightBarButtonItem?.isEnabled = false
          
        if isTitleTextViewEdited, isContentTextViewEdited {
            guard let newTitleText = createNoticeBoardView.titleTextView.text else { return }
            guard let newContentText = createNoticeBoardView.contentTextView.text else { return }
              
            firebaseManager.createNoticeBoard(title: newTitleText, content: newContentText) { success in
                if success {
                    self.navigationController?.popViewController(animated: true)
                    print("๊ฒŒ์‹œํŒ ์ƒ์„ฑ ์„ฑ๊ณต")
                }
                else {
                    self.navigationItem.rightBarButtonItem?.isEnabled = true
                    print("๊ฒŒ์‹œํŒ ์ƒ์„ฑ ์‹คํŒจ")
                }
            }
        }
        else {
            navigationItem.rightBarButtonItem?.isEnabled = true
        }
    }

์ด๋ฏธ์ง€ ๋น„์œจ ๋ฐ ๋‹ค์šด๋กœ๋“œ ์†๋„

์ด๋ฏธ์ง€ ๋‹ค์šด๋กœ๋“œ ์†๋„๊ฐ€ ๋А๋ฆผ

  • ์›์ธ : ์‚ฌ์šฉ์ž๊ฐ€ ๋ณด๋Š” ์ด๋ฏธ์ง€์— ๋น„ํ•ด ๋งค์šฐ ํฐ ์‚ฌ์ด์ฆˆ์˜ ์ด๋ฏธ์ง€๋ฅผ ์ €์žฅํ•˜๊ณ  ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ๋•Œ๋ฌธ, Firebase Storage๋Š” ๋”ฐ๋กœ ์บ์‹ฑ์ž‘์—…์„ ํ•ด์ฃผ์ง€ ์•Š์Œ
  • ํ•ด๊ฒฐ : ์ด๋ฏธ์ง€ ์‚ฌ์ด์ฆˆ ์กฐ์ ˆ์„ ๊ตฌํ˜„ํ•˜์—ฌ ์ €์žฅ, storage์— metadata์— ์žˆ๋Š” updated๊ฐ’๊ณผ ๋กœ์ปฌ์— ์žˆ๋Š” ์ด๋ฏธ์ง€ ๋ฐ์ดํ„ฐ๋ฅผ updated ๋น„๊ตํ•˜์—ฌ ๋‹ค๋ฅผ ๊ฒฝ์šฐ ์„œ๋ฒ„์—์„œ ์ด๋ฏธ์ง€๋ฅผ ๊ฐ€์ ธ์™€ ์บ์‹ฑ๋œ ์ด๋ฏธ์ง€๋ฅผ ๋ณ€๊ฒฝํ•จ
  1. ์ด๋ฏธ์ง€ ๋ฆฌ์‚ฌ์ด์ง• ์ž‘์—…
extension UIImage {
    func resizeImage(targetSize: CGSize) -> UIImage {
        let size = self.size
        let widthRatio = targetSize.width / size.width
        let heightRatio = targetSize.height / size.height

        var newSize: CGSize

        if widthRatio > heightRatio {
            newSize = CGSize(width: size.width * heightRatio, height: size.height * heightRatio)
        } else {
            newSize = CGSize(width: size.width * widthRatio, height: size.height * widthRatio)
        }

        let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)

        UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
        self.draw(in: rect)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return newImage!
    }
}
guard let smallImageData = image.resizeImage(targetSize: CGSize(width: 90, height: 90)).pngData(),
      let mediumImageData = image.resizeImage(targetSize: CGSize(width: 480, height: 480)).pngData() else { return }
let datas = [smallImageData, mediumImageData]
imageUpload(datas: datas, uid: uid)
  1. ์ด๋ฏธ์ง€ ์บ์‹ฑ ์ž‘์—…
final class CacheImage {
    var image: UIImage
    var updated: Date?
    
    init(image: UIImage, updated: Date?) {
	self.image = image
	self.updated = updated
    }
}
var cacheImage: CacheImage? = nil
if let image = imageCache.object(forKey: storagePath as NSString) {
    completion(.success(image.image))
    cacheImage = image
}
let storage = Storage.storage().reference(withPath: storagePath)
  
storage.getMetadata { metadata, error in
    if let error {
        completion(.failure(error))
        return
    }

    if let cacheImageUpdated = cacheImage?.updated,
       let storageDataUpdated = metadata?.updated,
       cacheImageUpdated == storageDataUpdated {
        return
    }
  					  .  
  					  .

๋ฐ์ดํ„ฐ๊ฐ€ ๋งŽ์€ ํ™”๋ฉด์—์„œ ๋А๋ฆฐ ์†๋„

  • ์›์ธ : ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ๊บผ๋ฒˆ์— ๊ฐ€์ ธ์™€์„œ ์ƒ๊ธด ๋ฌธ์ œ
  • ํ•ด๊ฒฐ : ํŽ˜์ด์ง€ ๋„ค์ด์…˜์„ ๊ตฌํ˜„ํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ 10๊ฐœ์”ฉ ๋‚˜๋ˆ ์„œ ๊ฐ€์ ธ์˜ค๋„๋ก ๊ตฌํ˜„
var query = defaultRef.queryOrderedByKey()
if let lastClubId {
    query = query.queryStarting(atValue: lastClubId)
}

query = query.queryLimited(toFirst: 10)

query.getData { error, datasnapshot in
				.
				.
// ์Šคํฌ๋กค๋ทฐ์—์„œ ์ผ์ • ๋†’์ด๊ฐ€ ๋„˜์–ด๊ฐ€๋ฉด ์ƒˆ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋„๋ก ๊ตฌํ˜„
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let offsetY = scrollView.contentOffset.y
        let contentHeight = scrollView.contentSize.height
        if offsetY > contentHeight - scrollView.frame.height && !isLoading {
            loadData()
        }
    }

iPhone 15 Pro

### ๊ธฐ๊ธฐ ๋ณ„ ๋ ˆ์ด์•„์›ƒ ์กฐ์ •

๊ธฐ๊ธฐ์— ๋”ฐ๋ผ์„œ ์ปดํฌ๋„ŒํŠธ์˜ ๋ ˆ์ด์•„์›ƒ์ด ๊นจ์ง

  • ์›์ธ : ๊ธฐ๊ธฐ ๋ณ„๋กœ ํ™”๋ฉด์˜ ํฌ๊ธฐ๊ฐ€ ๋‹ค๋ฆ„, ์˜คํ† ๋ ˆ์ด์•„์›ƒ์„ ์ •ํ™•ํ•œ ์ˆ˜์น˜๋กœ ์ง€์ •
    // ๋†’์ด๋ฅผ ์ˆ˜์น˜๋กœ ์„ค์ •
    meetingDescriptionTextView.snp.makeConstraints { make in
        make.top.equalTo(countMeetingNameLabel.snp.bottom).offset(Constant.margin4)
        make.centerX.equalTo(scrollView)
        make.left.right.equalTo(scrollView).inset(Constant.margin4)
        make.height.equalTo(160)
    }

    iPhone 15 Pro iPhone SE

  • ํ•ด๊ฒฐ : lessThanOrEqualTo๊ณผ greaterThanOrEqualTo ์ด์šฉํ•ด์„œ ๋ ˆ์ด์•„์›ƒ ์„ค์ •
    // ๋†’์ด์˜ ์ตœ๋Œ€, ์ตœ์†Œ ์ง€์ •
    meetingDescriptionTextView.snp.makeConstraints { make in
       make.top.equalTo(countMeetingNameLabel.snp.bottom).offset(Constant.margin4)
       make.centerX.equalTo(scrollView)
       make.left.right.equalTo(scrollView).inset(Constant.margin4)
       make.height.lessThanOrEqualTo(160)
       make.height.greaterThanOrEqualTo(100)
    }

    iPhone 15 Pro iPhone SE


About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Swift 100.0%