// String을 반환하는 클로저
let myName : String = {
// myName 으로 들어간다
return "정대리"
}()
print(myName)
let myRealName : (String) -> String = { (name: String) -> String in
return "개발하는 \(name)"
}
myRealName("쩡대리") // 개발하는 쩡대리 print로 감싸야 출력함
let myRealNameLogic : (String) -> Void = { (name: String) in
print("개발하는 \(name)")
}
클로저는 메소드로 생각하면 편함
// completion 이라는 클로저를 매개변수로 가지는 메소드 정의
func sayHi(completion: () -> void) {
print("sayHi() called")
sleep(2) // 2초 가량 멈추기
// completion 클로저 실행
completion()
}
// 메소드 호출부 에서 이벤트 종료를 알 수 있다
sayHi(completion:{
print("2초가 지났다. 1")
})
sayHi(){
print("2초가 지났다. 2")
}
sayHi{
print("2초가 지났다. 3")
} // called 2초 지났다, 2초간격으로 3번 출력
// 매개변수로서 데이터를 반환하는 클로저
// 매개변수를 2개 이상 추가하려면
// completion : (String, String) -> Void) {...} 로 사용하면 된다
func sayHiWithName(completion: (String) -> Void){
print("sayHiWithName() called")
sleep(2)
// 클로저를 실행과 동시에 데이터 반환
completion("hi guys~")
}
sayHiWithName(completion:{ (comment: String) in
print("2초 뒤 그가 말했다 ! comment: ", comment)
})
// called, 2초뒤 그가 말했다 higuys~ 출력
sayHiWithName(completion:{ comment in
print("2초 뒤 그가 말했다 ! comment: ", comment)
})
sayHiWithName{comment in
print("2초 뒤 그가 말했다 ! comment: ", comment)
}
sayHiWithName{
print("2초 뒤 그가 말했다 ! comment: ", $0)
} // 매개변수가 두개이면 $0, $1 로 작성
class MyFriend {
var name : String
init(_ name: String = "이름없음"){
self.name = name
print("init() MyFriend 가 메모리에 올라갔다. - ", self.name)
}
deinit{
print("deinit() 메모리에서 사라짐 - ", self.name)
}
var myFriend = MyFriend("쩡대리")
let aFriend = MyFriend()
weak var aFriendToBeDestoried = MyFriend("개발하는 정대리")
class Friend {
var name : String
init(_ name: String){
self.name = name
}
func sayHi(){
print("안녕?! 난 \(self.name) 라고 해")
}
}
class BestFriend : Friend {
// override로 부모의 메소드를 가져왔다.
override init(_ name: String) {
// super 로 부모의 메소드 사용
super.init("베프 " + name)
}
override func sayHi() {
super.sayHi()
}
func sayGoodBye(){
print("sayGoodBye() called")
}
}
let myFriend = Friend("쩡대리")
myFriend.sayHi()
let myBestFriend = BestFriend("영희")
// 난 베프 영희 라고 해 출력 자식에도 var name 이 있다고 생각하면 된다
myBestFriend.sayHi()
myBestFriend.name
// 키 값으로 한쌍인 딕셔너리 - 사물함과 비슷
// 키 : 값
var myFriends = ["bestFriend" : "쩡대리",
"highschool" : "영희"
]
// bestFriend 라는 열쇠로 내용물을 꺼냄
let myBestFriend = myFriends["bestFriend"]
let highSchoolFriend = myFriends["highschool"]
// 해당 키로 값을 꺼낼때 저장된 값이 없다면 default 로 기본 값을 가져오도록 설정 가능
let youtubeFriend = myFriends["youtube" , default: "친구없음"]
// 값 추가 및 변경 가능
myFriends["bestFriend"] = "개발하는 정대리"
let myBF = myFriends["bestFriend"]
myFriends["newFriend"] = "철수"
let newFriend = myFriends["newFriend"]
// updateValue 메소드로 값 추가 및 변경 가능
myFriends.updateValue("수잔", forKey: "girlFriend")
let girlFriend = myFriends["girlFriend"]
myFriends.updateValue("짹슨", forKey: "bestFriend")
let myBestFriend2 = myFriends["bestFriend"]
// 빈 딕셔너리를 만드는 방법 들
let emptyDictionary1 : [String : Int] = [:]
let emptyDictionary2 = [String : Int]()
let myEmptyDictionary : [String : Int] = Dictionary<String, Int>()
myFriends.count
for item in myFriends {
print("item : ",item)
}
// 상속이 불가능한 class
final class Friend {
var name : String
init(name: String){
self.name = name
}
}
// error
class BestFriend : Friend {
override init(name: String){
super.init(name: "베프 " + name)
}
}
// 자료형이 Error 인 enum
enum MismatchError: Error {
case nameMismatch
case numberMismatch
}
// throw 를 통해 에러를 밖으로 던진다
// 에러를 밖으로 보낸다고 메소드 반환 부분에 throws 표시
func guessMyName(name input: String) throws {
print("guessMyName() called")
if input != "쩡대리" {
print("틀렸다")
throw MismatchError.nameMismatch
}
print("맞췄다")
}
// - Parameter input: 사용자 숫자 입력
// - Returns: bool 맞췄는지 여부
func guessMyNumber(number input: Int) throws -> Bool {
print("guessMyNumber() called")
if input != 10 {
print("틀렸다")
throw MismatchError.numberMismatch
}
print("맞췄다")
return true
}
// 해당 메소드에서 에러가 던져져도 에러 처리를 안할려면 try에 ?를 붙여준다
// try? guessMyName(name: "이대리")
// do catch 를 이용해 외부로 던져진 에러를 잡아서 에러 처리가 가능
do {
try guessMyName(name: "이대리")
} catch {
print("잡은 에러: \(error)")
}
// 에러를 던지는 반환형이 있는 메소드의 경우에는
// 에러가 던져졌을때 데이터를 반환하지 않고 바로 catch블럭으로 들어가는 것을 볼 수 있다.
do {
let receivedValue = try guessMyNumber(number: 9)
} catch {
print("잡은 에러: \(error)")
}
class Friend {
var name : String
func changeName(newName: String){
self.name = newName
}
init(_ name: String){
self.name = name
}
}
var myFriend = Friend("쩡대리")
myFriend.changeName(newName: "개발하는 쩡대리")
myFriend.name
// 구조체의 경우
// struct 는 참조(메모리 주소)인 클래스와 다르기 때문에
// struct 구조의 멤버 변수 값을 변경(mutate) 하기 위해서는 mutating 키워드가 필요
struct BestFriend {
var name : String
mutating func changeName(newName: String){
self.name = newName
print("newName: ", newName)
}
}
var myBestFriend = BestFriend(name: "쩡대리")
myBestFriend.changeName(newName: "호롤롤로!")
var myNumberSet : Set<Int> = Set<Int>()
// 1,2,3 3개만 들어간다
myNumberSet.insert(1)
myNumberSet.insert(2)
myNumberSet.insert(2)
myNumberSet.insert(3)
// set 내부 값은 고유 해야한다
// 배열과 다르게 순서가 정해져있지 않다.
// 매번 출력되는 값들의 순서가 다르다
for aNumber in myNumberSet {
print("aNumber: ", aNumber)
}
var myBestFriends : [String] = ["철수", "영희", "수지"]
myBestFriends.contains("수지")
var myFriends : Set<String> = ["철수", "영희", "수지"]
// 콜렉션 [배열, 셋, 딕셔너리, 튜플] 등이 가지고 있는 기본 메소드 들을 제공한다.
myFriends.contains("쩡대리")
// 수지의 Set 인덱스를 가져온다.
// 인덱스가 없을수 있으므로 옵셔널을 언래핑하는 if let을 사용한다
// 인덱스가 없다면 nil을 반환하기 때문
if let indexToRemove = myFriends.firstIndex(of: "수지") {
print("indexToRemove: ", indexToRemove)
myFriends.remove(at: indexToRemove)
}
// 약속 이라고 생각하면 된다
/// **delegate, **able, **ing 이름을 붙이는 방식들
protocol Naming {
// 우리는 이런 변수를 가지고 있을겁니다 라고 약속
var name : String { get set }
// 우리는 이런 메소드를 가지고 있을겁니다 라고 약속
func getName() -> String
}
// 프로토콜에 맞지 않은 선언은 error 를 뜨게 해줌
struct Friend : Naming{
var name: String
func getName() -> String {
return "내 친구: " + self.name
}
}
var myFriend = Friend(name: "쩡대리")
myFriend.getName()
// 프로토콜 상속
protocol Naming {
var name: String { get set }
func getName() -> String
}
protocol Aging {
var age: Int { get set }
}
// 이름, 나이 프로토콜을 상속하는 사용자 프로토콜
protocol UserNotifiable : Naming, Aging {
}
// 두 프로토콜을 동시에 준수해야한다.
// 프로토콜 = 약속
class MyBestFriend: UserNotifiable {
var name: String = ""
var age: Int
func getName() -> String {
return self.name
}
init(_ name: String, _ age: Int){
self.name = name
self.age = age
}
}
struct MyFriend : UserNotifiable {
var name: String
func getName() -> String {
return self.name
}
var age: Int
}
// 프로토콜 확장
// 프로토콜에는 선언만 하고 로직을 담을 수 없다.
protocol Naming {
var lastname: String { get set }
var firstname: String { get set }
func getName() -> String
}
// 프로토콜을 확장 익스텐션하면 메소드의 로직을 담을 수 있다.
extension Naming {
func getFullname() -> String{
return self.lastname + " " + self.firstname
}
}
struct Friend : Naming {
var lastname: String
var firstname: String
func getName() -> String {
return self.lastname
}
}
let myFriend = Friend(lastname: "쩡", firstname: "대리")
myFriend.getName()
myFriend.getFullname()
// 프로토콜 associatedType
protocol PetHaving {
// associatedtype 을 통해 제네릭으로 어떠한 자료형이든 가질수 있다.
associatedtype T
var pets: [T] { get set }
// mutating 을 통해 스트럭트 에서 맴버 변수 값 변경
mutating func gotNewPet(_ newPet: T)
}
extension PetHaving {
mutating func gotNewPet(_ newPet: T){
self.pets.append(newPet)
}
}
enum Animal {
case cat, dog, bird
}
struct Friend : PetHaving {
// 애완동물이 Animal 내부 case들만 입력이 가능
var pets: [Animal] = []
}
struct Family : PetHaving {
// 애완동물이 String
var pets: [String] = []
}
// typealias 별칭으로 내가 원하는 것을 다르게 부를수 있다.
protocol Naming {
func getName() -> String
}
protocol Aging {
func getAge() -> Int
}
// 프로토콜 별칭 설정
// Naming이랑 Aging을 같이 쓴다는 의미
typealias Friendable = Naming & Aging
typealias FullNaming = Naming
struct Friend : Friendable {
var name : String
var age : Int
func getName() -> String {
return self.name
}
func getAge() -> Int {
return self.age
}
}
// 자료형, 클래스, 스트럭트, 클로저 등 모두 별칭 설정이 가능하다
typealias FriendName = String
var friendName : FriendName = "정대리"
typealias Friends = [Friend]
var myFriendsArray : Friends = []
// 클로저를 StringBlock 이라는 별칭으로 설정하였다.
typealias StringBlock = (String) -> Void
func sayHi(completion : StringBlock){
print("안녕하세요?")
completion("오늘도 빡코딩 하고 계신가요?")
}
sayHi(completion: { saying in
print("여기서 받음 : ", saying)
})
typealias MyType = MyClass.MY_TYPE
class MyClass {
enum MY_TYPE {
case DOG
case CAT
case BIRD
}
var myType = MyType.DOG
}
var myClass = MyClass()
myClass.myType = MyType.DOG
print("myClass.myType:", myClass.myType)
struct Pet {
init(){
print("Pet 이 생성되었다.")
}
}
struct Friend {
var name: String
// lazy 키워드로 바로 메모리에 올리지 않고 사용하는 시점에 메모리에 올려서 사용합니다.
lazy var pet : Pet = Pet()
init(_ name: String){
self.name = name
print("Friend 가 생성됨")
}
}
var myFriend = Friend("쩡대리")
// 접근했을때 Pet이 생성되서 메모리에 올라가는 걸 볼 수 있습니다.
myFriend.pet
매개변수로 클로저를 받고 클로저를 반환하는 함수
func getName(_ name: String) -> String {
return "내 이름은 \(name)"
}
var getNameClosure : (String) -> String
func sayHello( getName: (String) -> String, name: String) -> String {
return getName(name)
}
let resultOne = sayHello(getName: getName(_:), name: "호롤롤로")
// 1. sayHello의 매개변수로 getName을 받고
// 2. return의 getName에서 name으로 "호롤롤로"를 받아서 return
let numbers = [3, 7, 4, -2, 9, -6, 10, 1]
let stringNumbers : [String] = numbers.map { (aNumber: Int) -> String in
return "\(aNumber) 입니다."
}
let evenNumbers : [Int] = numbers.filter { aNumber in
return aNumber % 2 == 0
} // [4, -2, -6, 10]
let oddNumbers : [Int] = numbers.filter { aNumber in
return aNumber % 2 != 0
} // [3, 7, 9, 1]
var myArray = [3, 4, 88, 99, 5, 6, 7 , 8, 10, 20, 100]
var ascendingArray = myArray.sorted()
// sort는 원본이 바뀐다
myArray.sort()
var descendingArray = myArray.sorted(by: >)
myArray.sort(by: >)