기본 스타일 가이드
SwiftLint(코드 스타일 컨벤션)
let aaa // 상수선언
var bbb // 변수선언
let profile = "\(name)님은 \(birthDay)일이 생일입니다."
var 배열명 = ["첫번째", "두번째"]
//배열 선언(둘이 같음)
let apps = Array<String>()
let apps = [String]() // 선호되는 방식
var responseMessages = [200: "OK",
403: "Access forbidden",
404: "File not found",
500: "Internal server error"]
let httpResponseCodes = [200, 403, 301]
for code in httpResponseCodes {
if let message = responseMessages[code] {
print("Response \(code): \(message)")
} else {
print("Unknown response \(code)")
}
}
var emptyDict = [:]
func call(value: Int = 333) -> String {
print(value)
return "OK"
}
print(call(111)) // print: 111
print(call()) // print: 333
//파라미터 이름 생략
func hello(_ name: String, time: Int) {
// ...
}
hello("전수열", time: 3) // 'name:' 이 생략되었습니다.
//개수가 정해지지 않은 파라미터
func sum(_ numbers: Int...) -> Int {
var sum = 0
for number in numbers {
sum += number
}
return sum
}
sum(1, 2)
sum(3, 4, 5)
// 어떤 타입이든 변신 가능한 Any, AnyObject
let anyNumber: Any = 10
let anyString: Any = "Hi"
let anyInstance: AnyObject = Dog()
// Any나 AnyObject로 선언하는 것은 지양하는편이 좋다.
// Any를 특정 타입으로 변환시키는 다운 캐스팅
let number: Int? = anyNumber as? Int
// 타입 검사
print(anyNumber is Any) // true
print(anyNumber is String) // false
switch anyNumber {
case is Int: break
case is String: break
}
func get() -> (result1: String, result2: Int) {
return ("AAA", 111) // 튜플로 반환
}
var tup = get()
print(tup.result1, tup.result2) // AAA 111
struct Sample {
// 가변 프로퍼티
var mutableProperty: Int = 100
// 불변 프로퍼티
let immutableProperty: Int = 100
// 타입 프로퍼티
static var typeProperty: Int = 100
// 인스턴스 메서드
func instanceMethod() {
print("instance method")
}
// 타입 메서드
static func typeMethod() {
print("type method")
}
// 키워드도 `로 묶어주면 이름으로 사용할 수 있습니다
var `class`: String = "Swift"
// 가변 프로퍼티
var name: String = "unknown"
func selfIntroduce() {
print("저는 \(self.class)반 \(name)입니다")
}
}
class Person {
// 정적 프로퍼티
// static var 와 차이점은 override 유무
class var mom: String {
get {
return "Mommy"
}
}
let name: String // 옵셔널도 아니면서 초기화도 안한다면 에러가 난다
let age: Int
// 생성자
init() {
self.name = "none"
self.age = 0
}
// 생성자 오버로딩
init(name:String, age:Int) {
self.name = name
self.age = age
}
// 메소드
func sing() -> Void {
print("Let it go~")
}
}
print(Person.mom)
let p1 = Person(name:"Elsa", age:21)
p1.sing()
// 상속
class Anna : Person {
override func sing() {
print("Love is an open door~")
}
}
let anna = Anna(name: "Anna", age: 18)
anna.sing()
enum Month: Int {
case january = 1
case february
~ 쭉쭉 ~
case november
case december
func simpleDescription() -> String {
switch self {
case .january:
return "1월"
case .february:
return "2월"
~ 쭉쭉 ~
case .november:
return "11월"
case .december:
return "12월"
}
}
}
let december = Month.december
print(december.simpleDescription()) // 12월
print(december.rawValue) // 12
let october = Month(rawValue: 10)
print(october) // Optional(Month.october)
//옵셔널은 Enum 이었다!!
public enum Optional<Wrapped> {
case none
case some(Wrapped)
}
//사용법
let age: Int? = 20
switch age {
case .none: // `nil`인 경우
print("나이 정보가 없습니다.")
case .some(let x) where x < 20:
print("청소년")
case .some(let x) where x < 65:
print("성인")
default:
print("어르신")
}
// Obj-c의 카테고리 같은거임
extension String {
var length: Int {
return self.characters.count
}
func reversed() -> String {
return self.characters.reversed().map { String($0) }.joined(separator: "")
}
}
let str = "안녕하세요"
str.length // 5
str.reversed() // 요세하녕안
var sumClosure = {(a, b) -> Int in return a + b}
print(sumClosure(1, 2))
// 함수안의 함수
func helloGenerator(message: String) -> (String, String) -> String {swift
return { $1 + $0 + message }
}
// 고차함수를 이용한 클로저 활용
let arr1 = [1, 3, 6, 2, 7, 9]
let arr2 = arr1.map { $0 * 2 } // [2, 6, 12, 4, 14, 18]
func someFunctionThatTakesAClosure(closure: () -> Void) {
// function body goes here
}
// Here's how you call this function without using a trailing closure:
someFunctionThatTakesAClosure(closure: {
// closure's body goes here
})
// Here's how you call this function with a trailing closure instead:
someFunctionThatTakesAClosure() {
// trailing closure's body goes here
}
// 함수 외부에 클로저를 저장하는 예시
// 클로저를 저장하는 배열
var completionHandlers: [() -> Void] = []
func withEscaping(completion: @escaping () -> Void) {
// 함수 밖에 있는 completionHandlers 배열에 해당 클로저를 저장
completionHandlers.append(completion)
}
func withoutEscaping(completion: () -> Void) {
completion()
}
class MyClass {
var x = 10
func callFunc() {
withEscaping { self.x = 100 }
withoutEscaping { x = 200 }
}
}
let mc = MyClass()
mc.callFunc()
print(mc.x)
completionHandlers.first?()
print(mc.x)
// 결과
// 200
// 100
var _v:Int = 0
var value:Int {
get {//oldValue 값도 쓸 수 있음
return _v
}
set {
_v = newValue
print("_v=\(_v)") //_v=10
}
didSet { //willSet 도 있음
switch (value) {
case 0:
case 2:
default:
break;
}
}
}
print(value) // 0
value = 10
가드문에 걸리면 그 안의 조건문이 실행된다.
var myVar = 10
func checkNumGuard(X:Int?) {
guard let X = X where X != 10 else {
print("Error: X is 10!")
return
}
print ("all this code will be executed when X is not 10")
}
checkNumGuard(myVar) // 출력: Error: X is 10!
class Food {
var name: String
init(name: String) {
self.name = name
}
convenience init() {
self.init(name: "[Unnamed]")
}
}
Food() // name 값 "[Unnamed]" 인 인스턴스로 초기화
클래스나 구조체를 특정 타입(주로 Data, Json) 인코딩 디코딩 간편하게 해주기 위한것으로
클래스 인스턴스를 NSUserDefault 같은 곳에 저장하거나, 서버에서 Json값을 모델로 변환시킬 때 유용하다!
//구조체를 NSUserDefault에 저장하고 빼내는 예제
struct Person: Codable {
var name: String
}
let taylor = Person(name: "Taylor Swift")
//인코딩
let encoder = JSONEncoder()
if let encoded = try? encoder.encode(taylor) {
let defaults = UserDefaults.standard
defaults.set(encoded, forKey: "SavedPerson")
}
//디코딩
if let savedPerson = defaults.object(forKey: "SavedPerson") as? Data {
let decoder = JSONDecoder()
if let loadedPerson = try? decoder.decode(Person.self, from: savedPerson) {
print(loadedPerson.name)
}
}
//JSONEncoder 대신 PropertyListEncoder를 사용하여 plist로 관리할 수 있다.
//예제
func userData(for userID: String, completion: (Result<Data, Error>) -> Void) {
// 모든 것이 잘 풀렸을 경우:
completion(.success(myData))
// 일이 잘 안 풀린 경우:
completion(.failure(myError))
}
//이런식으로 위 메서드를 사용하면 된다.
userData(for: "jemmons") { result in
switch (result) {
case (.success(let data)):
do something with data...
case (.failure(URLError.timedOut)):
print("Connection timed out.")
...
}