'Swift'에 해당되는 글 61건

  1. 2021.04.01 lazy
  2. 2021.03.26 카메라 앱 만들기
  3. 2021.03.24 Scroll View
  4. 2021.03.22 Firebase / Cocoa Pods
  5. 2021.03.19 넷플릭스 스타일 앱 만들기 / 오픈 소스 가져오는 방법
  6. 2021.03.17 네트워킹
  7. 2021.03.15 List App
  8. 2021.03.13 뮤직 앱
  9. 2021.03.06 CollectionView
  10. 2021.03.04 Property / Method

lazy

Swift/문법 2021. 4. 1. 21:00

지연 저장 프로퍼티

- 저장 프로퍼티보다 지연 저장 프로퍼티를 사용하는 것의 주요 이점은 코드 블럭이 정확히 해당 변수의 읽기 작업이 일어날 때만 실행된다는 것

 

호출이 있어야 값을 초기화하는데, 이 때 lazy 사용

 

잘 사용하면 불필요한 성능저하나 공간 낭비를 줄일 수 있음

 

lazy는 반드시 var와 함께 쓰여야 함


기본적으로 lazy로 선언된 변수는 초기에는 값이 존재하지 않고 이후에 값이 생기는 것이기 때문에 let 으로는 선언될 수 없음

 

lazy는 struct와 class에서만 사용할 수 있음

'Swift > 문법' 카테고리의 다른 글

Property / Method  (0) 2021.03.04
Class / 상속 / 생성자  (0) 2021.03.03
Closure  (0) 2021.03.03
Structure / Protocol  (0) 2021.03.02
Array / Dictionary / Set  (0) 2021.03.01
Posted by khon98
,

카메라 앱 만들기

Swift 2021. 3. 26. 17:09

AVCaptureSession

- 카메라나 마이크 같은 인풋에서 들어오는 비디오 오디오 데이터를 아웃풋으로 연결시켜주는 중간 역할을 함

 

AVCaptureDeviceInput

- 미디어 소스를 제공해주는 카메라 혹은 마이크가 해당됨

 

AVCaptureOutput

- 인풋에 들어오는 데이터를 디스크에 쓰거나 아니면 그 데이터를 받아서 프로세싱을 할때 사용

 

사용자 권한은 info.plist에서 받을 수 있음

Privacy - Camera Usage Description - 카메라를 쓰겠다는 permisson

Privacy - Photo Library Usage Description - 갤러리를 쓰겠다는 permisson 추가

'Swift' 카테고리의 다른 글

Scroll View  (0) 2021.03.24
Firebase / Cocoa Pods  (0) 2021.03.22
넷플릭스 스타일 앱 만들기 / 오픈 소스 가져오는 방법  (0) 2021.03.19
네트워킹  (0) 2021.03.17
List App  (0) 2021.03.15
Posted by khon98
,

Scroll View

Swift 2021. 3. 24. 18:50

스크롤 뷰 생성하고 레이아웃을 맞췄는데도 생기는 오류 없애는 방법

1. 스크롤 뷰 생성

2. 생성한 스크롤 뷰 안에 ui뷰 생성

3. ui뷰를 스크롤 뷰의 leading, top, tralling, bottum, 전체 뷰의 equal width, equal height 연결

4. equal height의 multiplier 1, priority 250으로 설정(스크롤 뷰의 크기가 커질수도 있기 때문)

'Swift' 카테고리의 다른 글

카메라 앱 만들기  (0) 2021.03.26
Firebase / Cocoa Pods  (0) 2021.03.22
넷플릭스 스타일 앱 만들기 / 오픈 소스 가져오는 방법  (0) 2021.03.19
네트워킹  (0) 2021.03.17
List App  (0) 2021.03.15
Posted by khon98
,

Firebase / Cocoa Pods

Swift 2021. 3. 22. 22:06

Firebase

- 서버 자체를 서비스로 제공

- 데이터 저장, 실시간 데이터 동기화, 사용자 인증, 데이터 분석, A/B Testing 등 많은 기능을 제공

 

Cocoa Pods

- 외부 라이브러리 관리 모듈

- Firebase Ios SDK를 가져오게 도와주는 모듈

 

 

Cocoa Pods 설치 방법

- 구글에 Cocoa Pods 검색 후 사이트에 있는 sudo gem install cocoapods 복사

- 터미널 실행 > 붙여 넣기

- 비밀 번호 입력

 

Firebase SDK 설치 방법

1. Firebase 홈페이지 접속

 

2. 로그인 후 우측 상단 '콘솔로 이동' 클릭

 

3. 프로젝트 추가 클릭 > 프로젝트 이름 설정 > continue > continue > Default account for Firebase 선택 > 프로젝트 생성

 

4. ios 클릭

 

5. 번들 id 추가 후 '계속' 클릭

Bundle Identifier 입력

 

6. GoogleService-Info 파일 다운로드

 

7. 다운로드한 파일 xcode 프로젝트에 추가

 

8. firebase 홈페이지에서 next 클릭

 

9. 터미널 실행 후 생성한 xcode 프로젝트 폴더 주소 입력

( pwd는 현재 터미널에서 접근한 위치가 어딘지 알려주고,

cd 입력 후 원하는 주소 입력하면 해당 위치로 이동,

open . 입력하면 해당 폴더를 open )

- pod이 깔려 있어야 함 (확인 방법: 터미널에 pod --version 입력 후 버전이 나오면 설치가 되어 있는 거고 안 뜨면 설치가 되어 있지 않은 거)

 

10. pod init 입력 > 해당 파일에 podfile이 생성됨 해당 파일 열고 # Pods for Firebase_SDK_Install 밑에 pod 'Firebase/Analytics' 붙여 넣기

 

11. pod install 입력 > 파이어 베이스 홈페이지에서 '계속' 클릭 

 

12. 프로젝트 만든 폴더에 생성된 workspace 파일 열고

import Firebase / FirebaseApp.configure() 입력

 

13. 앱 실행하라고 하면 실행하면 되고 아니면 다음으로 넘어가면 됨

 

 

Realtime Database 만들기

1. 파이어 베이스 홈페이지에서 데이터 베이스를 만들 프로젝트 누르고 좌측 메뉴에 'Realtime Database' 클릭

 

2. 데이터 베이스 만들기 클릭 > 테스트 모드로 설정

 

3. workspace 생성된 파일에 podfile 실행 후 pod 'Firebase/Analytics' 밑에 pod 'Firebase/Database' 입력

 

4. 터미널에 pod install 입력

 

5. 코드 입력 / 오류 발생하면 클린 빌드하고 재실행

import Firebase / let db 코드 추가

 

6. 파이어 베이스 홈페이지 > 데이터 > add child 클릭 > 이름, 값 추가

 

 

 

 

더보기
import UIKit
import Firebase

class ViewController: UIViewController {
    
    @IBOutlet weak var dataLabel: UILabel!
    @IBOutlet weak var numOfCustomers: UILabel!
    
    let db = Database.database().reference()
    
    var customers: [Customer] = []

    override func viewDidLoad() {
        super.viewDidLoad()
        updateLabel()
        
        saveBasicTypes()
//        saveCustomers()
        
        fetchCustomers()
        
//        updateBasicType()
//        deleteBasicType()
    }
    
    func updateLabel() {
        // 파이어 베이스에 있는 데이터 firstdata에 있는 value 값을 가져옴
        db.child("firstdata").observeSingleEvent(of: .value) { snapshot in
            print("\(snapshot)")
            
            let value = snapshot.value as? String ?? ""
            
            DispatchQueue.main.async {
                self.dataLabel.text = value // dataLabel에 snapshot 값을 넣어 줌
            }
        }
    }
    
    @IBAction func createCustomer(_ sender: Any) {
        saveCustomers()
    }
    
    @IBAction func fetchCustomer(_ sender: Any) {
        fetchCustomers()
    }
    
    func updateCustomers() {
        guard customers.isEmpty == false else { return }
        customers[0].name = "khon50"
        
        let dictionary = customers.map { $0.toDictionary }
        db.updateChildValues(["customers": dictionary])
    }
    
    @IBAction func updateCustomer(_ sender: Any) {
        updateCustomers()
    }
    
    func deleteCustomers() {
        db.child("customers").removeValue()
    }
    
    @IBAction func deleteCustomer(_ sender: Any) {
        deleteCustomers()
    }
    
}



// MARK: Database에 데이터 가져와서 파싱하기
extension ViewController {
    func fetchCustomers() {
        db.child("customers").observeSingleEvent(of: .value) { snapshot in
            print("\(snapshot.value)")
            
            do {
                let data = try JSONSerialization.data(withJSONObject: snapshot.value, options: [])
                let decoder = JSONDecoder()
                let customers: [Customer] = try decoder.decode([Customer].self, from: data)
                self.customers = customers
                
                DispatchQueue.main.async {
                    self.numOfCustomers.text = "Num of Customers: \(customers.count)"
                }
            } catch let error {
                print("error: \(error.localizedDescription)")
            }
        }
    }
}

// MARK: Database에 데이터 추가
extension ViewController {
    func saveBasicTypes() {
        db.child("Int").setValue(3)
        db.child("Double").setValue(4.8)
        db.child("Str").setValue("String Value - 안녕")
        db.child("array").setValue(["a", "b", "c"])
        db.child("Dict").setValue(["ID": "khon", "age": 50, "city": "seoul"])
    }
    
    func saveCustomers() {
        let books = [Book(title: "abcd", author: "abcd"), Book(title: "efgh", author: "efgh")]
        
        let customer1 = Customer(id: "\(Customer.id)", name: "khon", books: books)
        Customer.id += 1
        let customer2 = Customer(id: "\(Customer.id)", name: "khon01", books: books)
        Customer.id += 1
        let customer3 = Customer(id: "\(Customer.id)", name: "khon02", books: books)
        Customer.id += 1
        
        db.child("customers").child(customer1.id).setValue(customer1.toDictionary)
        db.child("customers").child(customer2.id).setValue(customer2.toDictionary)
        db.child("customers").child(customer3.id).setValue(customer3.toDictionary)
    }
}

// MARK: Database 데이터 수정 및 삭제
extension ViewController {
    func updateBasicType() {
        db.updateChildValues(["Int": 6])
        db.updateChildValues(["Double": 7.9])
        db.updateChildValues(["Str": "Change String"])
    }
    
    func deleteBasicType() {
        db.child("Int").setValue(3)
        db.child("Double").setValue(4.8)
        db.child("Str").setValue("String Value - 안녕")
    }
}

struct Customer: Codable {
    let id: String
    var name: String
    let books: [Book]
    
    var toDictionary: [String: Any] {
        let booksArray = books.map { $0.toDictionary }
        let dict: [String: Any] = ["id": id, "name": name, "books": booksArray]
        return dict
    }
    static var id: Int = 0
}

struct Book: Codable {
    let title: String
    let author: String
    
    var toDictionary: [String: Any] {
        let dict: [String: Any] = ["title": title, "author": author]
        return dict
    }
}

'Swift' 카테고리의 다른 글

카메라 앱 만들기  (0) 2021.03.26
Scroll View  (0) 2021.03.24
넷플릭스 스타일 앱 만들기 / 오픈 소스 가져오는 방법  (0) 2021.03.19
네트워킹  (0) 2021.03.17
List App  (0) 2021.03.15
Posted by khon98
,

오픈 소스 가져오는 방법

1. SPM(Swift Package Manager)

2. Cocoa Pod

3. Carthage

 

SPM 사용 법

1. 오픈 소스 가져오려는 Url 주소 복사

2. xcode 상단 메뉴에 file > swift package > add package dependency

 

https://github.com/khon98/Netflix_St_App

'Swift' 카테고리의 다른 글

Scroll View  (0) 2021.03.24
Firebase / Cocoa Pods  (0) 2021.03.22
네트워킹  (0) 2021.03.17
List App  (0) 2021.03.15
뮤직 앱  (0) 2021.03.13
Posted by khon98
,

네트워킹

Swift 2021. 3. 17. 21:26

Postman을 통해서 네트워크 작업을 볼 수 있음

 

ios에서는 URLSession을 통해 네트워크 작업을 할 수 있음

 

Queue

- 컴퓨터 공학에서 말하는 자료 공학

- 먼저 들어온 값이 먼저 나가는 방식

 

네트워킹

- 기본적으로 HTTP라는 방법으로 Rest api를 이용해서 json데이터를 주고받음

 

Concurrency(동시성)

- 동시에 여러 가지 일을 수행하는 능력

- GCD와 Operration 통해서 동시성이 필요한 작업들을 관리해 줄 수 있음

- 사용자 인터랙션 처리, 네트워킹, 백그라운드에서 파일 다운로드, 파일 저장하고 읽기 같은 작업 수행 이러한 작업들을 스레드라고 함

 

Thread(스레드)

- 4개의 스레드가 있다고 가정, 4개의 스레드는 동시에 번갈아가면서 모든 작업을 함

- 메인 스레드는 사용자 인터렉션을 처리하면서 ui 표시하는 작업을 함

- 복잡한 계산이나 네트워크 느린 작업은 메인이 아닌 다른 스레드에서 처리해야 앱의 반응을 빠르게 가져갈 수 있음

 

 

HTTP

- 앱과 서버 간에 데이터를 주고받을 때 사용하는 통신 규약

- 동영상 스트리밍 할 때도 사용(HLS)

 

HTTP Request

- url창에 무언가를 입력하고 엔터를 눌렀을 때 하는 행위가 request 하는 방식

 

1. post: create

- 새로운 데이터를 해당 url에 생성을 요구할 때

 

2. get: read

- 해당 url에 있는 데이터를 보고 싶을 때

 

3. update: update

- 해당 url에 있는 데이터를 수정하고 싶을 때

 

4. delete: delete

- 해당 url에 있는 삭제하고 싶을 때

 

 

GCD

- 해야 할 일들을 만들어서 gcd에 넘기면 시스템에서 알아서 스레드를 할당해서 안전하게 수행시켜줌

- 스레드와 비슷한 개념

- gcd에서 사용하는 큐는 dispatch queue

- 테스크를 동기(Sync) & 비동기(Async)로 처리할 수 있음

 

Sync 

- 앞에 작업이 끝나고 나서 다음 일을 처리하는 방식

 

Async 

- 앞에 작업이 끝나지 않아도 다음 일을 시작하는 방식

- 해당하는 우선순위 작업에 따라 진행

- 다운로드하는 작업은 Async로 진행

더보기
// Async
// 일을 같이 처리
DispatchQueue.global(qos: .background).async {
    for i in 0...5 {
        print("A \(i)")
    }
}

// 우선 순위가 더 높기 때문에 먼저 마무리
DispatchQueue.global(qos: .userInteractive).async {
    for i in 0...5 {
        print("B \(i)")
    }
}

// Sync
// Sync는 먼저 일을 처리 후 그 다음 일을 처리
DispatchQueue.global(qos: .background).sync {
    for i in 0...5 {
        print("A \(i)")
    }
}

DispatchQueue.global(qos: .userInteractive).async {
    for i in 0...5 {
        print("B \(i)")
    }
}

 

Dispatch Queue

1. main queue

- 메인 스레드에서 작동하는 큐

- 시스템에서 제공

// main
DispatchQueue.main.async {
    let view = UIView()
    view.backgroundColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
}

 

2. global queue

- 시스템에 의해 관리되는 큐

- 큐에 들어가는 테스크의 우선순위를 qos 클래스를 통해서 표현할 수 있음

- 시스템에서 제공

 

Qos

우선순위가 높은 순

- 1. userinteractive

-- 바로 수행되어야 할 작업에 대해서 userinteractive 설정

 

- 2. userinitiated

-- 사용자 결과를 기다리는 작업에 사용

 

- 3. default

-- userinitiated 보다 좀 더 걸리는 작업에 사용

 

- 4. utility

-- 몇 초 ~ 몇 분 걸리는 작업에 사용

-- 네트워킹이나 파일 불러오기 같은 작업에 사용

 

- 5.background

-- 사용자에게 당장 인식될 필요가 없는 경우 사용

 

3. custom queue

- 큐를 직접 만들어서 사용해야 하는 경우

- 시스템에서 제공하지 않음

// global
DispatchQueue.global(qos: .userInteractive).async {
    // 가장 먼저 해줘야 하는 일
}

DispatchQueue.global(qos: .userInitiated).async {
    // 사용자가 기다리고 있으니 빨리 해줘야 하는 일
}

DispatchQueue.global(qos: .default).async {
    // 그냥 저냥 해도 되는 일
}

DispatchQueue.global().async { // default는 이런 식으로 표현 가능
    
}

DispatchQueue.global(qos: .utility).async {
    // 시간이 좀 걸리는 일들, 사용자가 당장 없어도 상관 없는 일들, 네트워킹, 큰 파일 다운로드
}

DispatchQueue.global(qos: .background).async {
    // 사용자한테 당장 필요하지 않은 일들, 뉴스데이터 미리 받기, 위치 업데이트, 영상 다운로드 등등
}

 

 

URLSession

- URLSession은 URLSessionConfiguration을 이용해서 생성을 하게 됨

- URLSessionTask를 만들 수 있음(URLSessionTask를 통해 서버와 통신함)

- URLSeesionDelegate을 통해 네트워킹 중간 과정을 확인할 수 있음

 

URLSessionConfiguration

- URLSessionConfiguration을 생성할 때는 URLSession 정책에 따라서 Default, Ephemeral, Background 세 가지 타입으로 만들 수 있음

 

1. Default

- 기본 통신할 때 사용

 

2. Ephemeral

- 쿠키나 캐시 같은 것을 저장하지 않게 정책을 가져갈 때 사용(예: 시크릿 모드)

 

3. Background

- 다운로드할 때 사용

 

URLSessionTask

1.URLSessionDataTask

- 기본적인 데이터를 받는 작업에 사용

- response 데이터를 메모리 상에서 처리

- 백그라운드 세션에 대한 지원이 안됨

 

2. URLSessionUploadTask

- 파일 업로드할 때 사용

 

3. URLSessionDownloadTask

- 파일 다운로드할 때 사용

 

더보기
import UIKit

// url
// 웹 리소스의 주소
let urlString = "https://itunes.apple.com/search?media=music&entity=song&term=Gdragon"
let url = URL(string: urlString)

url?.absoluteString // urlStrung에 입력된 값을 보여줌
url?.scheme // 어떤 방식으로 네트워킹을 하고 있는지 확인 시켜줌
url?.host
url?.path
url?.query // 검색에 대한 조건
url?.baseURL


let baseURL = URL(string: "https://itunes.apple.com")
let relativeURL = URL(string: "search?media=music&entity=song&term=Gdragon", relativeTo: baseURL)

relativeURL?.absoluteString
relativeURL?.scheme
relativeURL?.host
relativeURL?.path
relativeURL?.query
relativeURL?.baseURL



// URLComponents
var urlComponents = URLComponents(string: "https://itunes.apple.com/search?")
let mediaQuery = URLQueryItem(name: "media", value: "music")
let entityQuery = URLQueryItem(name: "entity", value: "song")
let termQuery = URLQueryItem(name: "term", value: "Gragon")

urlComponents?.queryItems?.append(mediaQuery)
urlComponents?.queryItems?.append(entityQuery)
urlComponents?.queryItems?.append(termQuery)

urlComponents?.url
urlComponents?.string
urlComponents?.queryItems

 

 

더보기
import UIKit

var urlComponents = URLComponents(string: "https://itunes.apple.com/search?")!
let mediaQuery = URLQueryItem(name: "media", value: "music")
let entityQuery = URLQueryItem(name: "entity", value: "song")
let termQuery = URLQueryItem(name: "term", value: "지드래곤")

urlComponents.queryItems?.append(mediaQuery)
urlComponents.queryItems?.append(entityQuery)
urlComponents.queryItems?.append(termQuery)
let requestURL = urlComponents.url!

let config = URLSessionConfiguration.default
let session  = URLSession(configuration: config)


struct Response: Codable {
    let resultCount: Int
    let tracks: [Track]
    
    enum CodingKeys: String, CodingKey {
        case resultCount
        case tracks = "results"
    }
}

struct Track: Codable {
    let title: String
    let artistName: String
    let thumbnailPath: String
    
    enum CodingKeys: String, CodingKey {
        case title = "trackName"
        case artistName
        case thumbnailPath = "artWorkUrl100"
    }
}


let dataTask = session.dataTask(with: requestURL) { (data, response, error) in
    guard error == nil else { return }
    
    guard let statusCode = (response as? HTTPURLResponse)?.statusCode else { return }
    let successRange = 200..<300
    
    guard successRange.contains(statusCode) else {
        // handle response error
        return
    }
    
    guard let resultData = data else { return }
    let resultString = String(data: resultData, encoding: .utf8)


// 파싱
    do {
        let decoder = JSONDecoder()
    
        // try - 해당 작업이 항상 성공 한다는 보장이 없음, 시도를 하다가 오류가 생기면 catch 구문으로 빠짐
        let response = try decoder.decode(Response.self, from: resultData)
    
        let tracks = response.tracks
    
        print("tracks: \(tracks.count) -\(tracks.first?.title), \(tracks.last?.thumbnailPath)")
    
    } catch let error {
       print("error: \(error.localizedDescription)") // 오류에 대한 설명은 localizedDescription에 나와 있음
    }
}

dataTask.resume()

'Swift' 카테고리의 다른 글

Firebase / Cocoa Pods  (0) 2021.03.22
넷플릭스 스타일 앱 만들기 / 오픈 소스 가져오는 방법  (0) 2021.03.19
List App  (0) 2021.03.15
뮤직 앱  (0) 2021.03.13
CollectionView  (0) 2021.03.06
Posted by khon98
,

List App

Swift 2021. 3. 15. 22:09

데이터 저장 방법

- NSCoding

- Property List

- Serialization

- Core Data

- Realm

 

많고 복잡한 데이터를 다루기에는 Core Data, Realm이 사용하기 좋음

작고 덜 복잡한 데이터는 NSCoding, Property List를 사용하여 쉽고 빠르게 구현

 

Codable

- NSCoding처럼 간단하고 적은 데이터로 관리하기 매우 적합한 기능들을 제공

 

 

오타, 빠진 거 없나 확인 잘하기

constraint를 outlet 연결 시 값 조정하면서 원하는 위치로 작동하나 확인하기

 

https://github.com/khon98/ListApp

'Swift' 카테고리의 다른 글

넷플릭스 스타일 앱 만들기 / 오픈 소스 가져오는 방법  (0) 2021.03.19
네트워킹  (0) 2021.03.17
뮤직 앱  (0) 2021.03.13
CollectionView  (0) 2021.03.06
MVVM 디자인 패턴  (0) 2021.03.04
Posted by khon98
,

뮤직 앱

Swift 2021. 3. 13. 01:41

미디어 관련 앱 개발시에는 AVFoundation을 사용(카메라, 비디오, 음악 어플을 만들때 주로 사용)

 

CollectionReusableView

- 섹션 헤더 뷰

 

AVPlayer

- 미디어를 플레이 시켜줌

 

싱글톤

- 앱 내에서 하나만 필요하고 필요할때 마다 여기저기 불려서 사용되게 하는 객체

- shared 키워드 사용

 

CMTime

- 0.1초를 구하고 싶은 경우

CMTime(seconds: 1, preferredTimescale: 10)

1초를 10번 나눈다

 

https://github.com/khon98/MusicApp

'Swift' 카테고리의 다른 글

네트워킹  (0) 2021.03.17
List App  (0) 2021.03.15
CollectionView  (0) 2021.03.06
MVVM 디자인 패턴  (0) 2021.03.04
Table View  (0) 2021.03.03
Posted by khon98
,

CollectionView

Swift 2021. 3. 6. 10:22

https://github.com/khon98/CollectionView_BountyList

 

BountyList_CollectionView

더보기

CocoaTouchClass

import UIKit

class BountyViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
    
    let viewModel = BountyViewModel()
    let bountyList = [30000000, 50, 5000000, 500000000, 10000000, 15000000, 200000000, 350000000]
    
    // segue를 수행하기 직전에 수행하는 것에 대해서 준비하는 메서드
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "showDetail" {
            
            let vc = segue.destination as? DetailViewController
            if let index = sender as? Int {
                
                let bountyInfo = viewModel.bountyInfo(at: index)
                vc?.viewModel.update(model: bountyInfo)
            }
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    // UICollectionViewDataSource
    // 셀을 몇개를 보여줄지
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return viewModel.numOfBountyInfoList
    }
    
    // 어떻게 표현할지
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "GridCell", for: indexPath) as? GridCell else {
            return UICollectionViewCell()
        }
        
        let bountyInfo = viewModel.bountyInfo(at: indexPath.item)
            cell.update(info: bountyInfo)
        cell.update(info: bountyInfo)
        return cell
    }
    
    // UICollectionViewDelegate
    // 셀이 클릭 됐을 때
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        print("\(indexPath.item)")
        performSegue(withIdentifier: "showDetail", sender: indexPath.item)
    }
    
    // UICollectionViewDelegateFlowLayout
    // 셀 사이즈 계산 / 다른 디바이스에서도 동일하게 나오기 위한 작업
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        
        // 높이와 간격 지정
        let itemSpacing: CGFloat = 10 // 아이템 간격
        let textAreaHeight: CGFloat = 65 // 텍스트 간격
        
        let width: CGFloat = (collectionView.bounds.width - itemSpacing)/2
        let height : CGFloat = width * 10/7 + textAreaHeight
        return CGSize(width: width, height: height)
    }
 
}

// custom cell 생성
class GridCell: UICollectionViewCell {
    @IBOutlet weak var imgView: UIImageView!
    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var bountyLabel: UILabel!
    
    func update(info: BountyInfo) {
        imgView.image = info.image
        nameLabel.text = info.name
        bountyLabel.text = "\(info.bounty)"
    }
}

// ViewModel
class BountyViewModel {
    let bountyInfoList: [BountyInfo] = [
        BountyInfo(name: "brook", bounty: 30000000),
        BountyInfo(name: "chopper", bounty: 50),
        BountyInfo(name: "franky", bounty: 5000000),
        BountyInfo(name: "luffy", bounty: 500000000),
        BountyInfo(name: "nami", bounty: 10000000),
        BountyInfo(name: "robin", bounty: 15000000),
        BountyInfo(name: "sanji", bounty: 200000000),
        BountyInfo(name: "zoro", bounty: 350000000)
    ]
    
    // 순위 정하기
    var sortedList: [BountyInfo] {
        let sortedList = bountyInfoList.sorted { prev, next in
            return prev.bounty > next.bounty
        }
        return sortedList
    }
    
    var numOfBountyInfoList: Int {
        return bountyInfoList.count
    }
    
    func bountyInfo(at index: Int) -> BountyInfo {
        return sortedList[index]
    }
}

 

 

 

CocoaTouchClass

import UIKit
class DetailViewController: UIViewController {
    
    @IBOutlet weak var imgView: UIImageView!
    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var bountyLabel: UILabel!
    
    @IBOutlet weak var NameLabelCenterX: NSLayoutConstraint!
    @IBOutlet weak var BountyLabelCenterX: NSLayoutConstraint!
    
    let viewModel = DetailViewMomdel()
    
    // 화면이 보이기 직전
    override func viewDidLoad() {
        super.viewDidLoad()
        updateUI()
        
        // 애니메이션 준비하는 과정
        prepareAnimation()
    }
    
    // 애니메이션
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        showAnimation()
    }
    
    // 애니메이션 들어가기 전 기본 세팅
    private func prepareAnimation() {
        // view 밖으로 내보내기
//        NameLabelCenterX.constant = view.bounds.width
//        BountyLabelCenterX.constant = view.bounds.width
        
        nameLabel.transform = CGAffineTransform(translationX: view.bounds.width, y: 0).scaledBy(x: 3, y: 3).rotated(by: 180)
        bountyLabel.transform = CGAffineTransform(translationX: view.bounds.width, y: 0).scaledBy(x: 3, y: 3).rotated(by: 180)
        
        nameLabel.alpha = 0
        bountyLabel.alpha = 0
    }
    
    private func showAnimation() {
//        // 밖으로 내보내진 값들을 원위치
//        NameLabelCenterX.constant = 0
//        BountyLabelCenterX.constant = 0
        
        // label 애니메이션 효과 추가
        // namelabel 애니메이션
        UIView.animate(withDuration: 0.7, delay: 0.5, usingSpringWithDamping: 0.6, initialSpringVelocity: 2, options: .allowUserInteraction, animations: {
            
            // affinetransform은 변형을 가하는건데 변형을 가하기 전에 모습은 identity로 사용
            self.nameLabel.transform = CGAffineTransform.identity
            self.nameLabel.alpha = 1
        }, completion: nil)
        
        // bountylabel 애니메이션
        UIView.animate(withDuration: 0.7, delay: 0.7, usingSpringWithDamping: 0.5, initialSpringVelocity: 2, options: .allowUserInteraction, animations: {
            
            self.bountyLabel.transform = CGAffineTransform.identity
            self.bountyLabel.alpha = 1
        
        }, completion: nil)
        
        // 이미지 애니메이션 효과 추가
        UIView.transition(with: imgView, duration: 0.4, options: .transitionFlipFromLeft, animations: nil, completion: nil)
    }
    
    func updateUI() {
        if let bountyInfo = viewModel.bountyInfo {
            imgView.image = bountyInfo.image
            nameLabel.text = bountyInfo.name
            bountyLabel.text = "\(bountyInfo.bounty)"
        }
    }
    
    // close 버튼을 누르면 창이 닫힘
    @IBAction func close(_ sender: Any) {
        dismiss(animated: true, completion: nil)
    }
}

class DetailViewMomdel {
    var bountyInfo: BountyInfo?
    func update(model: BountyInfo?) {
        bountyInfo = model 
    }
}

'Swift' 카테고리의 다른 글

List App  (0) 2021.03.15
뮤직 앱  (0) 2021.03.13
MVVM 디자인 패턴  (0) 2021.03.04
Table View  (0) 2021.03.03
버튼 관련 코드  (0) 2021.02.24
Posted by khon98
,

Property / Method

Swift/문법 2021. 3. 4. 13:45

Object는 Data와 Method로 이루어짐

 

Property

1. Stored Property(저장 프로퍼티)

- 값을 저장해서 변수로 사용

- didSet 사용 가능

 

2. Computed Property(연산 프로퍼티)

- 값을 직접 저장하지 않고 저장된 정보를 이용해서 가공 혹은 계산된 값을 제공할 때 사용

get과 set을 이용해서 CompuedProperty에도 값을 세팅할 수 있음

 

Setter가 필요하면 Computed Property 그렇지 않고

계산이 많이 필요하면 Method

많이 필요하지 않으면 Computed Property

 

3. Type Property

- 생성된 인스턴스와 상관없이 Struct 타입 혹은 Class 타입 자체의 속성을 정하고 싶을 때 사용

- static 사용

 

4. Lazy Property

- 해당 프로퍼티에 접근될 때 코드가 실행되는 프로퍼티

struct Store {

    // 데이터 / 프로퍼티 / Stored Property
    let loc: Location
    let name: String
    let deliveryRange = 2.0


    // 메소드
    func isDeliverable(userLoc: Location) -> Bool {
        let distanceToStore = distance(current: userLoc, target: loc)
        return distanceToStore < deliveryRange
    }
}


struct Lecture: CustomStringConvertible {
    
    // Computed Property
    var description: String {
        
        
    // 원하는 lec을 입력하면 해당 강의 이름과 강사 명 출력
    return "Title: \(name), Instructor: \(Instructor)" }
    
    let name: String
    let Instructor: String
    let Student: Int
    
}





struct Person {
    // Stored Property
    var firstName: String {
//        willSet {
//            print("will set: \(firstName) --> \(newValue)")
//        }
        
        // 초기 값에서 변경된 값을 알고 싶을 때
        didSet {
            print("did set: \(oldValue) --> \(firstName)")
        }
    }
    var lastName: String
    
    lazy var isPopular: Bool = {
        if fullname == "khon" {
            return true
        } else {
            return false
        }
    }()
    
    // Computed Property
    var fullname: String {
        get {
            return "\(firstName)\(lastName)"
        }
        
        set {
            // newVlaue = "khon 01"
            // khon 01에서 빈 공간을 기준으로 first는 khon, last는 01이 됨
            if let firstName = newValue.components(separatedBy: " ").first {
                self.firstName = firstName
            }
            
            if let lastName = newValue.components(separatedBy: " ").last {
                self.lastName = lastName
            }
        }
    }
    
    static let isAlien: Bool = false
}

// Type Property
var person = Person(firstName: "kh", lastName: "on")

person.firstName
person.lastName

// var로 설정해서 바꿀수 있음, let이면 변경 불가
 person.firstName = "on"
 person.lastName = "kh"

 person.firstName
 person.lastName

person.fullname
person.fullname = "khon 01"
person.firstName
person.lastName

Person.isAlien

person.isPopular

 

 

Method

import UIKit

struct Lecture {
    var title: String
    var maxStudents: Int = 10
    var numOfRegister: Int = 0
    
    // Method
    func remainSeats() -> Int {
        let remainSeats = maxStudents - numOfRegister
        return remainSeats
    }
    
    // struct안에 메서드가 Stored property를 변경 시킬 경우 mutating을 써줘야 함
    mutating func register() {
        // 등록된 학생 수 증가
        numOfRegister += 1
    }
    
    // type property
    static let target: String = "모든 학생"
    
    // type method
    static func 학원이름() -> String {
        return "Abc"
    }
}

var lec = Lecture(title: "ios")

lec.remainSeats()
lec.register()
lec.remainSeats()

Lecture.target
Lecture.학원이름()




// extention
struct math {
    static func abs(value: Int) -> Int {
        if value > 0 {
            return value
        } else {
            return -value
        }
    }
}
math.abs(value: -20)

// 확장
// 제곱과 반 값 메서드 추가
extension math {
    static func square(value: Int) -> Int {
        return value * value
    }
    
    static func half(value: Int) -> Int {
        return value/2
    }
}
math.square(value: 10)
math.half(value: 20)



var value: Int = 3

extension Int {
    func square() -> Int {
        return self * self
    }
    
    func half() -> Int {
        return self/2
    }
}
value.square()
value.half()

'Swift > 문법' 카테고리의 다른 글

lazy  (0) 2021.04.01
Class / 상속 / 생성자  (0) 2021.03.03
Closure  (0) 2021.03.03
Structure / Protocol  (0) 2021.03.02
Array / Dictionary / Set  (0) 2021.03.01
Posted by khon98
,