๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐ŸŽ iOS/๐Ÿ”ฅ ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ…

[iOS/Swift]์นด์นด์˜คํ†ก ๊ณต์œ ํ•˜๊ธฐ ๊ตฌํ˜„ 1.์ด๋ฏธ์ง€ URL ์„ค์ • + FileManager์— UIImage ์ €์žฅ

by MINT09 2024. 7. 5.

์šฐ๋ฆฌ ์„œ๋น„์Šค roome๋Š” ๋ฐฉํƒˆ์ถœ ํ”„๋กœํ•„์„ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์ฃผ๋œ ๊ธฐ๋Šฅ์ด๋‹ค. ๋•Œ๋ฌธ์— ์ด ํ”„๋กœํ•„์„ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ๊ณต์œ ํ•˜๋Š” ๊ฒƒ์ด ํ•„์ˆ˜์˜€๋‹ค. ๋„ค์ด๋ฒ„, ์ธ์Šคํƒ€ ๋“ฑ ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋งค์ฒด๋ฅผ ๊ณ ๋ฏผํ–ˆ๋Š”๋ฐ ํ”„๋กœํ•„ ์ด๋ฏธ์ง€๋ฅผ ๋ณด์—ฌ์ฃผ๋ฉด์„œ ํด๋ฆญ ์‹œ ์šฐ๋ฆฌ ์•ฑ์œผ๋กœ ์—ฐ๊ฒฐ์„ ํ•˜๋Š” ๊ฒƒ์—๋Š” ์นด์นด์˜ค๋งŒ์ด ์ ํ•ฉํ•˜๋‹ค๋Š” ๊ฒฐ๋ก ์ด ๋‚˜์™€ ์นด์นด์˜คํ†ก ๊ณต์œ ํ•˜๊ธฐ๋งŒ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค.

1. ํ๋ฆ„

๊ณต์œ ํ•˜๊ธฐ๊ฐ€ ์ด๋ฃจ์–ด์ง€๋Š” ๊ณผ์ •์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค. 

-----๋ณด๋‚ด๋Š” ์ด-----

1. ์‚ฌ์šฉ์ž๊ฐ€ ViewController์—์„œ ๊ณต์œ ํ•˜๊ธฐ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅธ๋‹ค. 

2. ViewModel์—์„œ KakaoShareApi๋ฅผ ์‚ฌ์šฉํ•ด ๊ณต์œ ์šฉ ํ…œํ”Œ๋ฆฟ์„ ์ƒ์„ฑํ•˜๊ณ , ์ „๋‹ฌํ•œ๋‹ค. 

3. ์ „๋‹ฌ ํ›„ ๋˜๋Œ์•„์˜จ๋‹ค.

-----๋ฐ›๋Š” ์ด-----

1. ํ™•์ธํ•˜๋Ÿฌ ๊ฐ€๊ธฐ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅธ๋‹ค.

2. -1) ์•ฑ ๋ฏธ์„ค์น˜ ์‹œ ์นด์นด์˜ค ๋””๋ฒจ๋กœํผ์Šค์˜ ํ”Œ๋žซํผ์— ์„ค์ •๋œ iOS ๋งˆ์ผ“์œผ๋กœ ์ด๋™ํ•œ๋‹ค.

    -2) ์•ฑ ์„ค์น˜ ์‹œ

          -a) background:  SceneDelegate์˜ openURLContexts๊ฐ€ ์‹คํ–‰๋œ๋‹ค.

          -b) Suspended: SceneDelegate์˜ willConnectTo์—์„œ ๋ถ„๊ธฐ ์ฒ˜๋ฆฌํ•˜์—ฌ urlContexts๊ฐ€ ์žˆ๋‹ค๋ฉด openURLContexts๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค. 

2. ์ด๋ฏธ์ง€ URL

๋ณด์—ฌ์ง€๋Š” ๊ฒƒ์€ ์œ„์™€ ๊ฐ™๋‹ค. 

1. ์ƒ์„ฑํ•œ ํ”„๋กœํ•„ ์ด๋ฏธ์ง€

2. Title = $(NICKNAME)๋‹˜์˜ ๋ฐฉํƒˆ์ถœ ํ”„๋กœํ•„ ๋„์ฐฉ! 

3. Description = ์ง€๊ธˆ ๋ฐ”๋กœ ๋ฃจ๋ฏธ์—์„œ ํ™•์ธํ•ด ๋ณด์„ธ์š”.

4. Button = ํ™•์ธํ•˜๋Ÿฌ ๊ฐ€๊ธฐ

์ด๋•Œ ํ”„๋กœํ•„ ์ด๋ฏธ์ง€๋ฅผ ๋„ฃ๋Š” ๊ฒƒ์ด ๋ฌธ์ œ์˜€๋‹ค. ์นด์นด์˜คํ†ก ๊ณต์‹ ํŽ˜์ด์ง€๋ฅผ ๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์„ค๋ช…์ด ์žˆ๋‹ค.

๋ฉ”์‹œ์ง€์— ๋„ฃ์„ ์ด๋ฏธ์ง€๋Š” URL ํ˜•ํƒœ๋กœ ๋ฉ”์‹œ์ง€ ํ…œํ”Œ๋ฆฟ ๊ตฌ์„ฑ ์‹œ์— ์ฒจ๋ถ€ํ•˜๊ฑฐ๋‚˜, ๋ฉ”์‹œ์ง€ ํ…œํ”Œ๋ฆฟ ๋„๊ตฌ์—์„œ ๋ฏธ๋ฆฌ ์—…๋กœ๋“œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ๊ธฐ์— ์ €์žฅ๋œ ์ด๋ฏธ์ง€ ํŒŒ์ผ์€ ์„œ๋ฒ„์— ์—…๋กœ๋“œํ•˜๊ณ  ์ด๋ฏธ์ง€ ํŒŒ์ผ URL ๊ฐ’์„ ๊ตฌํ•ด์•ผ ๋ฉ”์‹œ์ง€ ์ „์†ก์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฏธ์ง€ ํŒŒ์ผ URL์„ ๊ตฌํ•˜๊ธฐ ์–ด๋ ค์šด ๊ฒฝ์šฐ, ์›น ํŽ˜์ด์ง€ ์† ์ด๋ฏธ์ง€ ํŒŒ์ผ์„ ์นด์นด์˜ค ์„œ๋ฒ„๋กœ ์—…๋กœ๋“œํ•˜๊ฑฐ๋‚˜ ์Šคํฌ๋žฉํ•ด๋‘๋Š” ๊ธฐ๋Šฅ์„ ์ด์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŒŒ์ผ ์šฉ๋Ÿ‰ 5MB ์ดํ•˜ ์ด๋ฏธ์ง€๋งŒ ์—…๋กœ๋“œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์นด์นด์˜ค ์„œ๋ฒ„์— ์—…๋กœ๋“œ๋œ ์ด๋ฏธ์ง€๋Š” ์ตœ๋Œ€ 100์ผ๊ฐ„ ๋ณด๊ด€๋˜๊ณ , ๊ธฐ๊ฐ„์ด ์ง€๋‚˜๋ฉด ์ž๋™์œผ๋กœ ์‚ญ์ œ๋ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ์„œ๋ฒ„์—์„œ ์ด๋ฏธ์ง€ ํŒŒ์ผ์„ ๊ฐ€์ง€๊ณ  ์žˆ์ง€ ์•Š์œผ๋ฏ€๋กœ ์ด๋ฏธ์ง€ ํŒŒ์ผ์„ ์นด์นด์˜ค ์„œ๋ฒ„์— ์—…๋กœ๋“œ ํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•ด์ฃผ๋Š” url์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ๊ตฌํ˜„ํ•˜์˜€๋‹ค.

์ด๋•Œ ์ƒ์„ฑ๋œ ํ”„๋กœํ•„ ์นด๋“œ ์ด๋ฏธ์ง€๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด FileManager๋ฅผ ์‚ฌ์šฉํ•˜์˜€๋‹ค. ImageManager๋ฅผ ๋งŒ๋“ค์–ด FileManager์— ์ €์žฅํ•˜๊ฑฐ๋‚˜ ๊ฐ€์ ธ์™€์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„ํ•˜์˜€๋Š”๋ฐ, ํ”„๋กœํ•„ ์นด๋“œ ViewController์—์„œ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•˜๋ฉด ๊ทธ ์ด๋ฏธ์ง€๋ฅผ Data๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ FileManager์— ์ €์žฅํ•˜๊ณ  ์นด์นด์˜คํ†ก ์„œ๋ฒ„์— ์—…๋กœ๋“œํ•˜๊ธฐ ์œ„ํ•ด ์ด๋ฏธ์ง€๊ฐ€ ํ•„์š”ํ•  ๋•Œ ImageManager์—์„œ ๋‹ค์‹œ UIImage๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•ด์ค€๋‹ค.

class ImageManager {
    enum Identifiers: String {
        case squareCard = "squareCard"
        case rectangleCard = "rectangleCard"
    }
    
    //Data๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ FileManager์— ์ €์žฅ. 
    class func saveImageToDirectory(identifier: Identifiers, image: UIImage?) {
        let documentsDirectory = FileManager.default.urls(for: .documentDirectory,in: .userDomainMask).first!
        let imageName = identifier.rawValue
        let fileURL = documentsDirectory.appendingPathComponent(imageName, conformingTo: .png)
        
        do {
            if let imageData = image?.pngData() {
                try imageData.write(to: fileURL)
                print("Image saved at: \(fileURL)")
            }
        } catch {
            print("Failed to save images: \(error)")
        }
    }
    
    //FileManager์—์„œ ์ฐพ์•„์„œ Data๋ฅผ ๋‹ค์‹œ UIImage๋กœ ๋ณ€ํ™˜
    class func loadImageFromDirectory(identifier: Identifiers) -> UIImage? {
        let fileManager = FileManager.default
        let documents = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!
        let fileURL = documents.appendingPathComponent(identifier.rawValue, conformingTo: .png)
        
        guard fileManager.fileExists(atPath: fileURL.path) else {
            return nil
        }
        
        return UIImage(contentsOfFile: fileURL.path)
    }
}
//์นด์นด์˜ค ์„œ๋ฒ„์— ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ
private func updateImageToKakaoServer() {
	//ImageManager๋ฅผ ์‚ฌ์šฉํ•ด FileManager์— ์ €์žฅ๋˜์—ˆ๋˜ ์ด๋ฏธ์ง€ ๋ฐ›์•„์˜ด
    let image = ImageManager.loadImageFromDirectory(identifier: .squareCard)
        
    if let profileImage = image {
    	//ํ•ด๋‹น ์ด๋ฏธ์ง€๋ฅผ ์นด์นด์˜ค ๊ณต์œ  ์„œ๋ฒ„์— ์—…๋กœ๋“œ
        ShareApi.shared.imageUpload(image: profileImage) { (imageUploadResult, error ) in
            if let error = error { //์—…๋กœ๋“œ ์‹คํŒจ
                print(error)
            } else { //์—…๋กœ๋“œ ์„ฑ๊ณต
            print("imageUpload() success.")
            
            //์—…๋กœ๋“œ ์„ฑ๊ณต ํ›„ ํ•ด๋‹น url response ๋ฐ›์Œ.
            let url = imageUploadResult?.infos.original.url
            
            //์‚ฌ์šฉํ•  ํ…œํ”Œ๋ฆฟ์— ์ „๋‹ฌ
            self.useCustomTemplate(imageURL: url)
            }
        }
    }
}

https://apps.apple.com/kr/app/roome/id6503616766

 

‎roome

‎๋ฐฉ ํƒˆ์ถœ ํ”„๋กœํ•„ ์ œ์ž‘ ์„œ๋น„์Šค ๋ฃจ๋ฏธ๋ฅผ ํ†ตํ•ด ๋‚˜์˜ ์„ฑํ–ฅ์„ ๋น ๋ฅด๊ฒŒ ์ด๋ฏธ์ง€๋กœ ๋งŒ๋“ค์–ด ๋ณด์„ธ์š”. ๋ฃจ๋ฏธ๋Š” ๋ฐฉ ํƒˆ์ถœ์„ ์ข‹์•„ํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์ด ๋‚˜์˜ ์ทจํ–ฅ์„ ๋‹ด์€ ํ”„๋กœํ•„์„ ์ด๋ฏธ์ง€ 1์žฅ์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” ์„œ๋น„์Šค

apps.apple.com