Swift 기본

Yk velog·2024년 8월 5일

Swift

목록 보기
3/8

모델


Model

  • 데이터로 사용하는 구조체: 위에서 예시로 든 Person 구조체 같은거라고 생각할 수 있을 것 같다. struct Person {let name, birthDate} 이런 느낌.
  • 네트워크 로직: 네트워크 요청을 하고, 그 결과를 받아오는 기본적인 기능을 담은 네트워크 로직이 포함된다.
  • Persistance 로직: 메모리에 저장되는 데이터를 로드 및 세이브하는 로직이 포함된다.
  • 데이터 파싱 로직: 네트워크로 받아오든 내부 파일에서 받아오든, JSON 같은 데이터가 왔을 때 이를 파싱하는 로직도 포함한다.
  • Manager 객체(shared 객체): 구조체를 만들어두고 필요한 경우에는 어디서든 접근해 사용할 수 있도록 따로 Manager를 만드는 경우도 Model에 포함된다.

View

  • 주로 UIView를 상속해 만들어진 subclass
  • Core Animation
  • Core Graphics

Controller

  • Controller는 앱의 핵심 로직을 담고 있는 계층이다. Controller는 View, Model에 연결되어 그 중간의 역할을 하고 있다.
  • MVC 패턴 때문에 생겨난 컨트롤러 객체
  • 뷰와 리소스를 관리
  • UIViewController 상속

클로저

함수의 파라미터로 전달이 가능하거나 함수에서 리턴이 가능하거나 변수나 상수에 저장 및 할당이 가능함

  1. 변수나 상수에 저장 및 할당이 가능하다.
*// closureSample* 상수에 **할당

**let** closureSample = { (city: String) -> String **in**

"I'm in \(city)"

}

*//* 할당된 **클로저 **실행

closureSample("서울")
  1. 함수의 파라미터로 전달이 가능하다.
*//* 상수에 **클로저 **할당

**let** sayHello = { (name: String) -> String **in**

"Hello \(name)"

}

*//* 상수에 **클로저 **할당

**let** sayGoodbye = { (name: String) -> String **in**

"Goodbye \(name)"

}

*//* 함수의 **파라미터로 **클로저를 **전달받도록 **정의

**func** **greet**(**name**: String, **sayWhat**: (String) -> String) {

sayWhat(name)

}

*//* 함수 **파라미터로 **클로저 **전달

*//* 리턴값 *: Hello* 이름

greet(name: "Jaebin", sayWhat: sayHello)

*//* 함수 **파라미터로 **클로저 **전달

*//* 리턴값 *: Goodbye* 이름

greet(name: "Jaebin", sayWhat: sayGoodbye)

*//* 상수 **클로저를 **전달하지 **않고 **직접 **클로저를 **구현해 **전달 **가능

greet(name: "Jaebin", sayWhat: {( displayName: String) -> String **in**

"How are you \(displayName)?"

})
  1. 함수에서 리턴이 가능하다.
*//* 함수의 **리턴값으로 **클로저 **반환

**func** **saySomething**(**word**: String) -> (String) -> String {

**return** { (word) -> String **in**

"I said \(word)"

}

}

*//* 리턴된 **클로저를 **상수에 **할당

**let** say = saySomething("Hello")

*//* 클로저 **호출

*//* 리턴값 *: I said Hello*

say()

클로저를 왜 사용하는가

  1. 콜백과 비동기
func fetchData(completion: @escaping (Data?, Error?) -> Void) {
    // 네트워크 요청 수행
    // 요청이 완료되면 completion 클로저 호출
}

fetchData { data, error in
    if let data = data {
        print("Data received: \(data)")
    } else if let error = error {
        print("Error: \(error)")
    }
}

2.상태 캡쳐

func makeIncrementer(incrementAmount: Int) -> () -> Int {
    var total = 0

    let incrementer: () -> Int = {
        total += incrementAmount
        return total
    }

    return incrementer
}

let incrementByTwo = makeIncrementer(incrementAmount: 2)
print(incrementByTwo())  // 2
print(incrementByTwo())  // 4

3.고차함수

let numbers = [1, 2, 3, 4, 5]
let evenNumbers = numbers.filter { $0 % 2 == 0 }
print(evenNumbers)  // [2, 4]
  1. 객체 지향의 대안
let add: (Int, Int) -> Int = { $0 + $1 }
let subtract: (Int, Int) -> Int = { $0 - $1 }

print(add(3, 4))  // 7
print(subtract(10, 5))  // 5

weak self

ARC(Automatic reference Counting)를 이용해서 데이터 관리. 객체는 참조가 더 이상 필요하지 않할 때 자동으로 메모리 해체

클로저 같은 구조에서는 강한 참조가 순환 참조를 일으킬 수 잇음 → 두 개 이상의 객체가 서로를 강하게 참조하여 서로가 메모리에서 해체되지 않음 → 메모리 누수

weak self를 언제 사용하는가?

  • 이스케이핑 클로저 안에서 지연할당의 가능성이 있는 경우 (API 비동기 데이터 처리, 타이머 등)
    * 이스케이핑 클로저가 아닌 일반 클로저에서는 Scope안에서 즉시 실행되므로 Strong Reference Cycle을 유발하지 않으므로, weak self를 사용할 필요가 없다.
  • 클로저가 객체에 대한 지연 deallocation 가능성이 있는 경우

네트워크 통신

override func viewDidload(){
	let url = "..."
	let apiURI : URL! = URL(string:url) // URl 변환
	
	let apidata = try ! Data(contentOf:apiURI)
	
	let log = NSString(data: apidata, encoding: String.Encoding.utf8.rawValue) ?? ""
	NSLog("Api result = \(log)")
}
  • String 말고 NSString을 사용하는 이유 : NSString(Foundation framework)은 Data객체를 문자열로 변환 해주는 메소드 지원. String은 직접 변환 메소드가 없음
    • String :
      • 언어 수준에서 정의된 구조체
      • Swift 기본 문자열 객체
    • NSString :
      • 프레임워크 수준에서 정의된 클래스
      • Objective-c 기본 문자열 객체
💡 IOS 9 부터 ATS(app transport security) 신설 : ssl 보안 프로토콜을 사용하지 않는 네트워크에 접속하려면 Info.plist 파일에서 특정 설정을 추가해줘야 함. ssl 설정은 서버사이드

ATS 설정

  1. Info.plist 파일 우클릭
  2. [Open AS] → [Source Code]
  3. 코드 수정
<key>NSAppTransportSecurity</key>
<dict>
	<key>NSAllowArbitraryLoads</key>
	<true/>
</dict>

데이터 파싱

overrid func viewDidload(){
	...
	do{
	//jsonObject -> NSDictionary // jsonArray -> NSArray
	let apiDictionary =  
		try JSONSerialization.jsonObject(with: apidata,options:[]) as! NSDictionary //options : 파싱 옵션 (없어서 공란)
	
	let hoppin = apiDictionary["hoppin"] as! NSDictionary
	let movies = hoppin["movies"] as! NSDictionary
	let movie = movies["movie"] as! NSArray
	
	for row in movie {
		 let r = row as! NSDictionary
		 let mvo = MovieVO()
		 
		 mvo.title = r["title"] as? String
		 mvo.description = r["description"] as? String
		 mvo.thumbnailImage = r["thumbnailImage"] as? String
		 mvo.detail = r["linkUrl"] as? String
		 mvo.rating = ((r["ratingAverage"] as? NSString).doubleValue)
		 
		 self.list.append(mvo)
		}
	}.catch { }
}

0개의 댓글