๐ŸŒฑ SeSAC

[SeSAC] 220812 TIL

taeeekki 2022. 8. 15. 14:00

๋Œ์•„๋ณด๋ฉฐ

์ƒˆ์‹น ๊ณผ์ •์„ ์‹œ์ž‘ํ•˜๊ณ  ๋ฒŒ์จ 30๋ฒˆ์งธ TIL์ด๋‹ค. (1, 2์ผ์ฐจ TIL์€ ์–ด์ฉŒ๋‹ค ๋ณด๋‹ˆ ๋นผ๋จน๊ฒŒ ๋˜์—ˆ์ง€๋งŒ) ์ฐธ ์‹œ๊ฐ„ ๋น ๋ฅด๋‹ค... ์ฒ˜์Œ์—๋Š” ์™„๋ฒฝํ•˜๊ฒŒ ์“ฐ๊ณ  ์‹ถ์–ด์„œ ๋ฏธ๋ฃจ๋‹ค๊ฐ€ ์ •๋ง ๋งŽ์ด ๋ฐ€๋ ธ์—ˆ๋Š”๋ฐ ์ด๋Ÿฌ๋‹ค๊ฐ€ ํ•˜๋‚˜๋„ ๋ชป ์“ธ ๊ฒƒ ๊ฐ™์•„์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ ํ•„๊ธฐํ•ด ๋’€๋˜ ๊ฑฐ ์งค๋ง‰ํ•˜๊ฒŒ ์˜ฌ๋ฆฌ๋Š” ํ˜•ํƒœ๋กœ ๋ฐ”๊พธ์—ˆ๋‹ค. ๋‚˜์ค‘์— ๋‹ค์‹œ ์ฐพ์•„๋ณผ ์ˆ˜ ์žˆ๋Š” ํ‚ค์›Œ๋“œ๋ฅผ ๋ชจ์•„๋†“์•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด ์ถฉ๋ถ„ํžˆ ์ข‹์€ ์ž์‚ฐ์ด ๋˜์ง€ ์•Š์„๊นŒ ์‹ถ๋‹ค. (30์ผ์ฐจ๊นŒ์ง€ ๊ทธ๋ž˜๋„ ๋ช‡ ์ž ์ ์œผ๋ ค๊ณ  ๋…ธ๋ ฅํ•œ ๊ฒƒ์€ ์นญ์ฐฌํ•œ๋‹ค.)

 

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

 

์˜์‹์˜ ํ๋ฆ„๋Œ€๋กœ ๋ช‡ ์ž ์ ์œผ๋ฉด์„œ


 

๋ฏธ๋””์–ด ๊ด€๋ จ

  1. ์‚ฌ์ง„ ์ดฌ์˜
  2. ๊ฐค๋Ÿฌ๋ฆฌ ์ ‘๊ทผ
  3. ๊ฐค๋Ÿฌ๋ฆฌ ์ €์žฅ

๐Ÿž UIImagePickerController - ์ปค์Šคํ…€ ๋ถˆ๊ฐ€, ์‚ฌ์ง„ ์ดฌ์˜
๐ŸŽฅ AVFoundation - ์ปค์Šคํ…€ (๋ฏธ๋””์–ด ๊ด€๋ จํ•œ ์„ธ๋ถ€ ์ฒ˜๋ฆฌ)
๐ŸŒ† PHPickerViewController - iOS 14์ด์ƒ, ๊ฐค๋Ÿฌ๋ฆฌ ์ ‘๊ทผ, ๊ฐค๋Ÿฌ๋ฆฌ ์ €์žฅ, ๋‹ค์ค‘ ์„ ํƒ

 

 


 

YPImagePicker

  • ์ธ์Šคํƒ€ ๊ทธ๋žจ๊ณผ ๊ฐ™์€ ์ด๋ฏธ์ง€, ๋น„๋””์˜ค ํ”ผ์ปค
  • Third-party ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • ๊ธฐ๋ณธ ImagePicker๋Š” ์ปค์Šคํ…€์ด ์ œํ•œ์ ์ด๊ธฐ ๋•Œ๋ฌธ์—, ์ž‘์—… ๊ธฐํ•œ ๋ฐ ๊ทœ๋ชจ ๋“ฑ์„ ๋ณด๊ณ  ์ ์ ˆํ•˜๊ฒŒ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ด์šฉํ•˜๋„๋ก ํ•˜์ž.
  • TLPhotoPicker๋ผ๊ณ  ๋˜ ๋งŽ์ด ์“ฐ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ YPImagePicker๊ฐ€ ๋” ๋งŽ์ด ์“ฐ์ธ๋‹ค๊ณ  ํ•œ๋‹ค.

์ž์„ธํ•œ ์ž‘๋™ ๋ฐฉ๋ฒ•์€ ๊ณต์‹ ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜๋„๋ก ํ•˜์ž.

let picker = YPImagePicker()
picker.didFinishPicking { [unowned picker] items, _ in
    if let photo = items.singlePhoto {
        print(photo.fromCamera) // Image source (camera or library)
        print(photo.image) // Final image selected by the user
        print(photo.originalImage) // original image selected by the user, unfiltered
        print(photo.modifiedImage) // Transformed image, can be nil
        print(photo.exifMeta) // Print exif meta data of original image.
        
        self.imageView.image = photo.image
    }
    picker.dismiss(animated: true, completion: nil)
}
present(picker, animated: true, completion: nil)

 


 

UIImagePickerController

iOS 14.0 ์ด์ƒ ๋ถ€ํ„ฐ๋Š” ๊ฐค๋Ÿฌ๋ฆฌ ์ ‘๊ทผ, ์ €์žฅ ๊ฐ™์€ ๊ฒฝ์šฐ๋Š” PHPickerViewController๋ฅผ ์ด์šฉํ•˜๋„๋ก ํ•˜์ž.

์นด๋ฉ”๋ผ

guard UIImagePickerController.isSourceTypeAvailable(.camera) else {
    return
}

picker.sourceType = .camera
picker.allowsEditing = true // ํŽธ์ง‘ํ™”๋ฉด ๋“ฑ์žฅ

present(picker, animated: true)

์•จ๋ฒ”

guard UIImagePickerController.isSourceTypeAvailable(.photoLibrary) else {
    return
}

picker.sourceType = .photoLibrary
picker.allowsEditing = false // ํŽธ์ง‘ํ™”๋ฉด ๏ฟฝX

present(picker, animated: true)

์‚ฌ์ง„ ์ €์žฅ

if let image = imageView.image {
    UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
}

๋ธ๋ฆฌ๊ฒŒ์ดํŠธ ๋ฉ”์„œ๋“œ

๊ธฐ๋ณธ์ ์œผ๋กœ UIImagePickerController๋Š” ๋„ค๋น„๊ฒŒ์ด์…˜ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์ƒ์† ๋ฐ›๊ณ  ์žˆ๋‹ค. ๊ทธ๋ž˜์„œ ์•„๋ž˜์— UINavigationControllerDelegate๋„ ํ•จ๊ป˜ ์ฑ„ํƒํ•ด์ฃผ๊ณ  ์žˆ์Œ.

extension CameraViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {

    // UIImagePickerController - ์‚ฌ์ง„์„ ์„ ํƒํ•˜๊ฑฐ๋‚˜ ์นด๋ฉ”๋ผ ์ดฌ์˜ ์งํ›„ ์‹คํ–‰
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        // - ์›๋ณธ, ํŽธ์ง‘, ๋ฉ”ํƒ€ ๋ฐ์ดํ„ฐ ๋“ฑ infoKey
        // - ๊ฐค๋Ÿฌ๋ฆฌ ์ƒ์— ์žˆ๋Š” ์ด๋ฏธ์ง€๋Š” originalImage
        if let image = info[UIImagePickerController.InfoKey.editedImage] as? UIImage {
            self.imageView.image = image
            dismiss(animated: true)
        }
    }
    
    // UIImagePickerController 5. ์ทจ์†Œ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ
    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        // code
    }
}

 


 

Clova ์–ผ๊ตด ์ธ์‹ API + MultipartFormData

๋ฌธ์ž์—ด์ด ์•„๋‹Œ ํŒŒ์ผ, ์ด๋ฏธ์ง€, PDF ํŒŒ์ผ ์ž์ฒด๊ฐ€ ๊ทธ๋Œ€๋กœ ์ „์†ก ๋˜์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋ž˜์„œ ํŒŒ์ผ์„ ํ…์ŠคํŠธ ํ˜•ํƒœ๋กœ ์ธ์ฝ”๋”ฉํ•˜์—ฌ ์„œ๋ฒ„๋กœ ์ „์†กํ•ด์•ผ ํ•œ๋‹ค. ๊ฒฐ๊ตญ ์ด ํ˜•ํƒœ๋„ body์— ๋‹ด์•„๋ณด๋‚ด๋Š” post ์š”์ฒญ์˜ ํ•œ ํ˜•ํƒœ๋ผ๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

import Alamofire
import SwiftyJSON

@IBAction func clovaFaceButtonTapped(_ sender: UIButton) {
    let url = "https://openapi.naver.com/v1/vision/celebrity"
    
    let headers: HTTPHeaders = [
        "X-Naver-Client-Id": "-",
        "X-Naver-Client-Secret": "-",
        "Content-Type": "multipart/form-data"
    ]
    
    // UIImage๋ฅผ ํ…์ŠคํŠธ ํ˜•ํƒœ(๋ฐ”์ด๋„ˆ๋ฆฌ ํƒ€์ž…)๋กœ ๋ณ€ํ™˜ํ•ด์„œ ์ „๋‹ฌ
    // MIME Type
    guard let imageData = imageView.image?.jpegData(compressionQuality: 0.5) else { return }

    AF.upload(multipartFormData: { multipartFormData in
        multipartFormData.append(imageData, withName: "image")
    }, to: url, headers: headers)
    .validate(statusCode: 200...500)
    .responseData { response in
        switch response.result {
        case .success(let value):
            let json = JSON(value)
            print(json)
            
        case .failure(let error):
            print(error)
        }
    }
}

Content-Type

์–ด๋–ค ํŒŒ์ผ์˜ ์ข…๋ฅ˜๊ฐ€ ์ „์†ก๋˜๋Š”์ง€ ๋ช…์‹œํ•ด์ค„ ํ•„์š”๊ฐ€ ์žˆ๋‹ค. ์—ฌ๋Ÿฌ ํŒŒ์ผ์„ ์—…๋กœ๋“œ ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๋ผ๋ฉด ํ—ค๋”์— Content-Type์„ multipart/form-data๋กœ ๋ช…์‹œํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

UIImage๋ฅผ ๋ฐ”์ด๋„ˆ๋ฆฌ ํƒ€์ž…์œผ๋กœ ๋ณ€ํ™˜

// pngData()๋ผ๋Š” ๋ฉ”์„œ๋“œ๋„ ์žˆ๋‹ค.
// ํฌ๊ธฐ๊ฐ€ ํฐ ์ด๋ฏธ์ง€๋ฅผ ์„œ๋ฒ„๋กœ ๋ณด๋‚ด๋ ค๊ณ  ํ•˜๋ฉด ํ†ต์‹ ์ด ์•ˆ๋˜๋Š” ๊ฒฝ์šฐ๋„ ์žˆ๋Š”๋ฐ ์•„๋ž˜์™€ ๊ฐ™์ด ์••์ถ•ํ•ด์„œ ๋ณด๋‚ด๋ฉด ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.
guard let imageData = imageView.image?.jpegData(compressionQuality: 0.5) else { return }