2017년 11월 10일 금요일

iTunes File Sharing (iTunes 파일 공유) @@ in Swift4.0 - Xcode9.0 iOS11

iTunes File Sharing 을 하면 디바이스를 iTunes 와 연결했을때 어플리케이션의 도큐멘트에 접근하여 공유할 수 있는 공유폴더를 사용할 수 있다.



1. info.plist 권한 수정

info.plist를 열어 아래 이미지 처럼 "Application supports iTunes file sharing" 키값을 추가하고
"YES"로 변경합니다. 




2. iPhone을 Mac에 연결하십시오. 아이튠즈 실행 (iPhone에 테스트용 어플리케이션을 설치했는지 확인)

3. 기기를 클릭 한 다음 왼쪽 메뉴 옵션에서 '앱'을 클릭합니다. > 파일 공유 선택하고 드래그하여 파일을 추가

4. 코드를 작성, 디버깅하여 어플리케이션의 도큐멘트에 복사된 파일이 추가 된 것을 확인

<참고 코드>
// 앱 도큐멘트 파일 리스트 확인
let fileManager = FileManager.default
do {
//도큐멘트 파일 경로를 가져옵니다.
let destPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
// 접근한 경로의 디렉토리 내 파일 리스트를 불러옵니다.
let items = try fileManager.contentsOfDirectory(atPath: destPath)
print("Count \(items.count)")
  for item in items {
    print("Found \(item)")
  }
} catch {
  print("Not Found item")
}



2017년 11월 2일 목요일

Property(프로퍼티) - Lazy Stored Properties (지연 저장 프로퍼티) @@ Swift4.0

지연 저장 프로퍼티 (Lazy Stored Properties)

1.정의

지연 저장 프로퍼티(lazy stored property)는 처음 사용 할때 까지 초기 값이 계산되지 않은 프로퍼티 입니다. 지연 저장 프로퍼티는 호출이 있어야 값을 초기화 하며 선언할때 앞에 lazy를 작성하여 나타냅니다.

* 지연 저장 프로퍼티는 인스턴스 초기화가 완료될때까지 초기 값을 가져올 수 없기 때문에, 항상 변수(var키워드 사용)로 선언해야 합니다. 상수 는 인스턴스가 완전히 생성되기 전에 초기화 해야 하므로 필요할때 값을 할당하는 지연 저장 프로퍼티와는 맞지 않습니다.

2.특징

 - 지연 저장 프로퍼티는 주로 복잡한 클래스나 구조체를 구현할 때 많이 사용

 - 외부요인에 의해 초기화가 완료될때가지 값을 알 수 없는 프로퍼티의 값을 초기화 할때 유용

 - 필요한 경우가 아니면 그때까지 수행되서는 안되는 복잡하거나 계산이 오래걸리는 프로퍼티가 필요한 경우 유용

 - 지연 저장 프로퍼티를 잘 사용하면 불필요한 성능저하나 공간 낭비를 줄일 수 있습니다.

<예제코드>

class DataImporter {

  var fileName = "data.txt"

}

class DataManager {

lazy var importer = DataImporter()

var data = [String]()

}

let manager = DataManager()

manager.data.append("Some data")

manager.data.append("Some more data")

// 이 코드를 통해 프로퍼티에 접근할때 importer 프로퍼티의 DataImporter가 생성됨


print(manager.importer.fileName)

주의!
다중 스레드 환경에서 지연 저장 프로퍼티에 동시다발적으로 접근할 때에는 한번만 초기화 된다는 보장이 없습니다. 생성되지 않은 지연저장 프로퍼티에 많은 스레드가 비슷한 시점에 접근한다면, 여러번 초기화 될 수 있습니다.


출처 : 야곰님의 스위프트 프로그래밍
출처 : http://kka7.tistory.com/88

Property(프로퍼티) - Stored Property (저장 프로퍼티) @@ Swift4.0

저장 프로퍼티 

- 구조체 -
struct S_Point {
  var x : Int
  var y : Int
}

// 구조체는 기본적으로 저장 프로퍼티를 매개변수로 갖는 이니셜라이저가 있습니다. 
let testPoint = S_Point(x: 10, y: 10)

- 클래스 -
class Position{
  var point : S_Point // << stored property 'point' without initial value prevents synthesized initializers 컴파일 에러 발생 

  let name : String // << stored property 'name' without initial value prevents synthesized initializers 컴파일 에러 발생

// 프로퍼티 기본값이 지정되어 있지 않다면 이니셜라이저를 따로 정의해주어야 합니다. 정의하지 않으면 위 컴파일 에러 발생 

  init(name : String, currentPoint : S_Point) {
    self.name = name
    self.point = currentPoint
  }
// 이니셜라이저 정의 후 컴파일 에러 사라짐 
}

// 이니셜라이저를 호출함으로써 초기값을 할당해야 인스턴스가 생성됩니다. 
let testPoint2 = Position(name: "tester", currentPoint: testPoint)

구조체는 프로퍼티에 맞는 이니셜라이저를 자동으로 제공하지만 클래스는 그렇지 않습니다. 하지만 클래스의 저장 프로퍼티의 초기값을 지정해주면 따로 이니셜라이저를 구현하지 않아도 됩니다.


class CustomPosition {
  var name : String = "tester" // << 초기값을 지정했기 때문에 이니셜라이저 없어도 컴파일 에러 발생 안함
  var age : Int? // 인스턴스 생성 시 프로퍼티에 값이 필요 없다면 프로퍼티를 옵셔널로 선언가능
}

let customName : CustomPosition = CustomPosition()
print(customName.name) // "tester" 출력
print(customName.age) // "nil" 출력

// 옵셔널 프로퍼티의 값을 알게 되었을때 할당
customName.age = 10
print(customName.age) // "Optional(10)"
print(customName.age!) // 옵셔널 벗기기 "10"

Property(프로퍼티) - 정의, 종류 @@ Swift4.0


1. 정의

프로퍼티 : 클래스, 구조체 또는 열거형 등에 관련된 값을 뜻함
메서드 : 특정타입에 관련된 함수

struct FixedPoint{
  var firstPoint : Int // << 프로퍼티
  let secondPoint : Int
}

var rangePoint = FixedPoint(firstPoint: 10, secondPoint: 10)
rangePoint.firstPoint = 11
// rangePoint.secondPoint = 11  >> 컴파일 에러 (let secondPoint 상수는 값 변경 안됨)

let rangePoint2 = FixedPoint(firstPoint: 20, secondPoint: 20
// rangePoint2.firstPoint = 22 >> 컴파일 에러 ( let rangePoint2 상수는 값 변경 안됨)


2.프로퍼티 종류

 저장 프로퍼티 (Stored Property) : 인스턴스의 변수 또는 상수, 구조체와 클래스에서만 사용가능

 연산 프로퍼티 (Computed Property) : 특정 연산을 실행한 결과값, 클래스, 구조체, 열거형에 사용

 타입 프로퍼티 (Type Property) : 특정타입에 사용

* 프로퍼티 감시자 : 프로퍼티의 값이 변할 때 값의 변화에 따른 특정 액션을 실행합니다.


2017년 10월 27일 금요일

Data Type : enum(열거형) @@ Swift4.0

enum(열거형)


열거형은 연관된 항목들을 묶어서 표현할 수 있는 타입
열거형은 배열이나 딕셔너리 같은 타입과 다르게 프로그래머가 정의해준 항목 값 외에는 추가/ 수정이 불가능
* switch 구문과 함께 사용할때 유용하게 사용할 수 있습니다.


열거형을 사용하는 경우

 - 제한된 선택지를 주고 싶을때
 - 정해진 값 외에는 입력받고 싶지 않을때
 - 예상된 입력 값이 한정되어 있을때


기본선언

enum School{
    case primary
    case elementary
    case middle
    case high
    case college
    case university
    case graduate
}

또는 "," 를 이용해 한줄로 표현

enum School {
    case primary, elementary, middle, high, college, university, graduate
}


열거형 변수의 생성 및 값 변경

var types : School = School.primary

var typeName : School = .graduate

typename = .elementary


열거형의 원시 값(Raw Value) 지정과 사용

enum Schooltype : String{
    case primary = "유치원"
}

let schoolNameText = Schooltype.primary
print("저의 학교는 \(schoolNameText.rawValue) 입니다")   //   "저의 학교는 유치원 입니다." 


열거형의 원시 값 일부 지정 및 자동 처리
일부 항목만 원시 값을 적용 시 나머지 값은 스위프트에서 알아서 자동처리

enum Numbers : Int{
    case zero
    case one
    case two
    case ten = 10
}

print(Numbers.zero.rawValue)   // 0
print(Numbers.ten.rawValue)  //  10


열거형 초기화
원시 값 정보를 알 경우 원시 값을 통해 열거형 변수 또는 상수를 생성, 올바르지 않는 원시 값을 통해  생성하려고 하면 nil 반환

enum Numbers : Int{
    case zero
    case one
    case two
    case ten = 10
}

let newNumber = Numbers(rawValue : 0)  // zero
var noneNumber = Numbers(rawValue : 4)  //  nil


 연관 값

enum MainDish{
    case pasta(taste : String)
    case pizza(dough : String, topping : String)
}

var dinner : MainDish = MainDish.pasta(taste: "크림")  //  pasta("크림")
dinner = .pizza(dough: "치즈크러스트", topping: "불고기")   //  pizza(dough: "치즈크러스트", topping: "불고기")

*순환열거형

indirect 키워드 사용

- 특정 항목에 순환 열거형 항목 명시 
   case 키워드 앞에 
   enum AriExpression{
      case number (Int)
      indirect case add (AriExpression, AriExpression)
   }

- 열거형 전체에 순환 열거형 명시
   enum 키워드 앞에
  indirect enum AriExpression{
      case number (Int)
      case add (AriExpression, AriExpression)
    }




출처 : 야곰님의 스위프트 프로그래밍


2017년 10월 22일 일요일

Data Type : 세트(Set) @@ Swift 4.0

세트 (Set)


세트는 같은 타입의 데이터를 순서 없이 하나의 묶음으로 저장하는 형태의 컬렉션 타입입니다.
세트 내의 값은 모두 유일한 값, 즉 중복된 값이 존재하지 않습니다.

*순서가 중요하지 않거나 각 요소가 유일한 값이어야 하는 경우에 사용

1. 세트의 선언과 생성

//  빈 세트의 생성
var emptySet : Set<String> = Set<String>()
var emptySet : Set<String> = []

// 대괄호를 이용해 초기화
var names : Set<String> = ["name1", "name2", "name3","name4"]

*Array에서 사용가능한 축약형(Array<Int>  -> [Int])이 Set에서는 불가능 사용 불가능 
 var names : String = ["name1", "name2", "name3","name4"]
 print(type(of: names))  // Array<String>

위 축약형을 사용할 경우 타입 추론에 의해 컴파일러는 Set 가 아닌 Array로 타입을 지정합니다.

2. 프로퍼티 

isEmpty  //  빈 값 체크 (Bool)
count  // 중복된 값은 허용하지 않아 카운팅 되지 않습니다.

3. 추가 및 삭제
// 추가
names.insert("name5")

// 삭제
names.rem("name5")


4. 세트의 활용 

- 집합 연산-

let englishClassStudent : Set<String> = ["john", "chulsoo", "yagom"]
let koreaClassStudent : Set<String> = ["jenny", "yagom", "chulsoo", "haha", "minsoo"]

<교집합>
let intersectSet : Set<String> = englishClassStudent.intersection(koreaClassStudent)
print(intersectSet)  //  ["yagom", "chulsoo"]

<여집합의 합>
let symmetricDiffSet : Set<String> = englishClassStudent.symmetricDifference(koreaClassStudent)
print(symmetricDiffSet)  //  ["john", "haha", "minsoo", "jenny"]

<합집합>
let unionSet : Set<String> = englishClassStudent.union(koreaClassStudent)
print(unionSet)  //   ["john", "yagom", "chulsoo", "haha", "minsoo", "jenny"]

<차집합>
let subtractSet : Set<String> = englishClassStudent.subtracting(koreaClassStudent)
print(subtractSet)  //  ["john"]


- 포함관계 연산 - 

print(새.isDisjoint(with: 포유류))   //  서로 베타적인지 - true

print(새.isSubset(of: 동물))   //  새가 동물의 부분집합 인가 - true

print(동물.isSuperset(of: 포유류))   //  동물은 포유류의 전체 집합인가 - true

print(동물.isSuperset(of: 새))  //  동물은 생의 전체 집합인가 - true


출처 : 야곰님의 스위프트 프로그래밍

2017년 10월 18일 수요일

Xcode 퀵헬프 사용 & 마크업 적용한 주석 사용

Xcode 에는 레퍼런스 문서의 요약된 내용을 보여주는 퀵헬프라는 기능이 있습니다.
코드작성중 레퍼런스 문서로 이동하지 않고 데이터타입이나 메서드 등의 간단한 정보를 확인할 수있는 아주 유용한 기능입니다.

<퀵헬프 보기>

원하는 항목(변수, 상수, 함수, 메서드, 타입 등등) 위에 마우스 커서를 놓고

option 키를 누른 상태로 클릭 or command + option + 2

통해 퀵헬프를 확인 가능합니다.


<마크업 형식에 따라 주석작성>

원하는 항목 (상수, 변수, 함수 등)에 마우스 커서를 위치한 후 

command + option + / 


ex)
enum HelloError : Error{
    case noName
    case unknown
}

HelloError 위에 마우스 커서를 위치 한 후 단축키를 누르면 (command + option + / )


/// <#Description#>
///
/// - noName: <#noName description#>
/// - unknown: <#unknown description#>
enum HelloError : Error{
    case noName
    case unknown
}

이렇게 마크업이 적용된 주석이 생성됩니다.

주석의 내용을 바꾸어 주고 퀵헬프 단축키를 누르면

/// 오류 타입의 열거형입니다.
/// - noName: 이름을 전달받지 못했을 때 발생하는 오류
/// - unknown: 알 수 없는 오류
enum HelloError : Error{
    case noName
    case unknown
}

원하는 항목 커서위치 > option 키를 누른 상태로 클릭 or command + option + 2




이렇게 퀵헬프 창에 나타납니다.


더 자세한 내용은 Markup Formatting Reference 를 참조하세요


출처 : 야곰님의 스위프트 프로그래밍


2017년 10월 17일 화요일

Data Type : Array (배열) @@ Swift 4.0

배열 (Array)

배열은 같은 타입의 데이터를 일렬로 나열한 후 순서대로 저장하는 형태의 컬렉션 타입입니다.

let 키워드 사용해 상수로 선언 시 변경할 수 없는 배열이 되고 var 키워드를 사용해 변수로 선언 시 변경 가능한 배열이 됩니다.


1. 배열의 선언과 생성


대괄호를 사용하여 배열 표현
var names : Array<String> = ["tester", "mary", "john"]

위와 동일한 배열  *[String]은 Array<String>의 축약 표현입니다.
var names : [String] = ["tester", "mary", "john"]

var namesArray : [Any]  = [Any]() //  Any 데이터를 요소로 갖는 빈 배열 생성
var namesArray : [Any]  = Array<Any> // 위 선언과 같은 동작 하는 코드

* 배열의 타입을 정확히 명시 했다면 [] 만으로 빈 배열 생성할 수 있습니다.
var emptyArray : [Any] = []
print(emptyArray.isEmpty)  // true

2. 배열의 사용


var names : Array<String> = ["tester", "mary", "john"]

1)  접근

print(names[2])   //   "john"
print(names[3])   //  에러 발생
print(names.index(of: "john"))  //   2
print(names.index(of: "me"))   // nil
print(names.first)  // "tester"
print(names.last)  //  "john"

2) 삽입

names.insert("tom", at:2)
print(names)  // ["tester", "mary", "tom", "john"]

names.insert(contentsOf : ["won"," ban"], at:4)
print(names)  //   ["tester", "mary", "tom", "john", "won", "ban"]

3) 제거

let firstItem:String = names.removeFirst()
let lastItem:String = names.removeLast()
let indexItem:String = names.remove(at: 1)

print(firstItem)  //  "tester"
print(lastItem)   //  "ban"
print(indexItem)  //  "tom"
print(names)  //   ["mary", "john", "won"]

4) 범위

print(names[0...1])  //  ["tester", "mary"]





출처 : 야곰님의 스위프트 프로그래밍






2017년 10월 16일 월요일

Swift 코드 테스트 할 수 있는 웹사이트 & 모바일

웹사이트


1. IBM Swift SandBox

https://swift.sandbox.bluemix.net/

 :  플레이그라운드와 유사한 모습으로 스위프트 코드 작성 및 실행 가능
    인기있는 스위프트 소스코드를 볼 수 있고 간단한 예제 소스 코드도 많음


2. 구름 IDE

https://ide.goorm.io/

 : 국내의 클라우드 통합 개발 환경, 컨테이너를 생성하여 가상 리눅스 환경에서 프로젝트 관리가 가능하며, 별도의 플러그인 등을 설치하지 않고도 온라인에서 직접 빌드 및 실행 가능
   리눅스 터미널 환경에서 스위프트 패키지 매니저를 사용할 수 있기 때문에 외부 라이브러리를 가져와서 프로젝트도 구현 할 수 있음.
   회원 가입을 하면 내프로젝트를 반영구적으로 저장,관리 할 수 있음
   스위프트 외에도 여러 프로그래밍 언어를 지원하며 Node.js, Spring, JSP, Arduino 등의 개발환경 제공
   클라우드 서버에서 바로 웹 서비스를 실행하여 운영 할 수도 있습니다.


모바일

iPad 용 플레이그라운드

앱스토어에서  Swift Playgrounds 검색 하여 설치

아이패드에서 스위프트 코드를 작성하고 테스트해볼 수 있는 어플리케이션




출처 : 야곰님의 스위프트 프로그래밍 책

2017년 10월 13일 금요일

switch문 @@ Swift4.0

switch 구문 기본

switch 입력 값 {
 case 비교 값 1 :
       실행 구문
 case 비교 값 2:
       실행 구문
       fallthrough  //  switch 구문의 case 를 연속 실행, fallthrough 사용 시 switch 구문을 탈출 하
                                   지 않고 아래 case로 넘어갑니다
 case 비교 값 3, 비교 값 4, 비교 값 5 :  //  한번에 여러 값을 비교할 수 있습니다.
       실행 구문
       break  //  break 키워드를 통해 종료 가능 -> 선택사항
 defult:  //  한정된 범위가 명확하지 않다면 default 는 필수 입니다.
       실행 구문
}

출처 : 야곰님의 스위프트 프로그래밍


2017년 9월 21일 목요일

Application Loader로 앱 업로드 (use Application Loader) @@ in Swift4.0 - Xcode9.0 iOS11

이번 업데이트로 앱을 업로드할 때 원인모를 오류들이 발생하여 Application Loader을
이용해 앱을 업로드했습니다.
매번 업데이트 때마다 문제가 생기니 이 방법에 익숙해지는 것이 좋을듯하여 정리하였습니다.


1. Application Loader 실행

Xcode의 메뉴중에 Open Developer Tool >  Application Loader 을 실행 시킵니다.



실행하면 아래 이미지처럼 나타납니다. 참고로 전 버전에선 "앱 전송" 말고도 "인앱구매" 라는 항목이 있었는데 사라졌네요




일단 Application Loader(어플리케이션 로더) 통해 앱을 전송해서 올리려면 ipa파일이 필요합니다.



2. ipa 파일 생성

ipa 파일 생성 방법은 앱스토어에 앱 업로드 시 사용하는 방법과 같습니다. 
Xcode > Product > Archive 를 실행합니다.

* Archive 가 활성화가 되어있지 않는 상태라면 핸드폰을 연결하여 빌드하고 다시 메뉴를 열어보시면 Archive 가 활성화 됩니다.




아래 화면으로 넘어갔다면 Upload to App Store.. 가 아닌 Export 를 눌러줍니다.


App Store 에 등록한것처럼 몇 가지 선택항목 체크 후 폴더 경로를 정해주면 해당 경로로
ipa 파일이 생성됩니다.



3. Application Loader를 이용한 앱 업로드

이제 처음에 실행했던 Application Loader 에서 선택버튼을 누른뒤 ipa 파일을 선택해주면 업로드가 됩니다.


2017년 8월 16일 수요일

타입 별칭(typealias) 사용 @@ Swift 4.0

typealias


스위프트에서 기본으로 제공하는 데이터 타입이든, 사용자가 임의로 만든 데이터 타입이든 이미 존재하는 데이터 타입에 임의로 다른 이름을 부여 할 수 있다.
 
typealias MyInt = Int
typealias YourInt = Int

let age : MyInt = 100  //  MyInt 는 Int 의 다른 이름입니다.
var year : YourInt = 2080  //  YourInt 는 Int 의 다른 이름입니다.


// MyInt, YourInt 둘다 Int 이기 때문에 같은 타입으로 취급 가능합니다.

age = year

2017년 8월 7일 월요일

Data Type : Dictionary - 딕셔너리 (사전) @@ Swift 4.0

딕셔너리

딕셔너리는 키와 값으로 구성된 요소를 순서 없이 저장하는 컬렉션입니다.
사전과 유사한 구조를 가지고 있으며 키는 단어, 값은 뜻으로 비유할 수 있습니다.

*키 값은 딕셔너리에서 값을 유일하게 식별해야 하기 때문에 하나의 딕셔너리에는 중복된 키가 
존재할 수 없습니다.

1. 종류

 Foundation 컬렉션 : NSDictionary, 가변클래스인  NSMutableDictionary 제공
   - 문자열 키를 사용 하며 저장되는 객체의 자료형 제한을 하지 않음
 Swift 컬렉션에선 Dictionary
   - 참조형식과 값 형식을 모두 저장, 요소의 자료형이 동일해야됨


2. 딕셔너리 기본 구조

  [키1 : 값1, 키2 : 값2, 키n : 값n]
  [:] // 빈 딕셔너리


3. 선언과 초기화

// Swift Dictionary
 let dictionary = ["a" : "SYD", "b" : "LHR", "c" : "GMP"]

// Foundation Dictionary 
 let nsWords : NSDictionary = ["a" : "SYD", "b" : "LHR", "c" : "GMP"]


4. 빈 딕셔너리 선언

 // Swift Dictionary
 let dictionary1 : Dictionary<String, String> = [:]
 let dictionary2 : [String : String] = [:]
 let dictionary3 = [String : String]()

 // Foundation Dictionary 
 let nsDic = NSMutableDictionary()

5. 딕셔너리 요소의 수

 let dictionary = ["a" : "SYD", "b" : "LHR", "c" : "GMP"]
 let dictionaryCount = dictionary.count


6. 요소에 접근

 var dictionary = ["a" : "SYD", "b" : "LHR", "c" : "GMP"]

  - 읽어오기
     let readingDic =  dictionary["a"]  // readingDic = "SYD"
  - 값 업데이트
     dictionary["a"] = "Sydney"
     dictionary.updateValue("updateString", forKey: "b") //메소드 사용
  - 지우기
     dictionary["a"] = nil
     dictionary.removeValue(forKey: "b") //메소드 사용
  
    
 7. 프로퍼티

  isEmpty // 빈 값 = true
  count  //   요소 개수 확인






2017년 7월 27일 목요일

변수(Variables) 와 상수(Constants) @@ Swift4.0


1. 변수 - Mutable (변하는 값)

저장된 값을 마음대로 변경할 수 있는 요소입니다.
변수의 이름과 저장할 값의 크기를 선언하면 메모리에 변수를 위한 저장공간이 생성됩니다.
var 사용하여 변수 선언

  var 변수이름 : 자료형
  ex) var a : Int


만일 변수의 수가 많고 동일한 자료형을 가지고 있다면 한줄에 여러 개의 변수를 선언

  var 변수1, 변수2, 변수3..변수n:Int
  var a, b, c: Int



다른 자료형의 변수 선언 시

  var a: Int, b:Float, c:String

변수 초기화
: 값을 최초로 저장하는 것을 초기화 라고 합니다.
* 변수를 선언한 후엔 반드시 적절한 값으로 초기화 해야합니다!

  var 변수이름 : 자료형 = 초기값
  var a : Int = 0





2. 상수  - Immutable (변하지 않는 값)

상수는 변수와 매우 유사하지만 초기값을 할당한 후에 값을 변경할 수 없습니다.
let 을 사용하여 상수 선언

선언과 초기화

  let 상수이름 : 자료형 = 초기값

  ex)상수 a 선언과 100으로 초기화
  let a : Int = 100


*상수값 변경 시 컴파일 에러 발생


  let a:Int // 상수 선언
  a = 0 // 초기화
  let b = a // 컴파일 에러 발생


3. 상수를 사용하면 좋은경우

- 파일이나 네트워크를 통해 읽어온 값을 변경 없이 사용 시

- 여러 소스를 함께 사용하는 고정값을 저장 시

- 여러 스레드에서 동시 접근해야 하는 값

- 컴파일러 최적화를 통해 더 나은 성능을 얻고 싶을 시

이 외엔 변수 사용


4. 변수, 상수 이름 정의 규칙

1. 띄어쓰기 안됨
2. CamelCase (낙타표기법) : 첫글자는 소문자로 시작, 첫번째 단어를 제외한 모든 단어의 첫 문자를 대문자 사용 
ex) let programmingLanguage = "swift"
3. 숫자로 시작 안됨
4. 공백사용 안됨
5. 수학적 기호 사용 안됨

























2017년 7월 20일 목요일

Swift3에서 GCD 사용(Grand Central Dispatch) @@ Swift3.0



GDC란?

Grand Central Dispatch는 줄여서 GCD라고 하는데, 강력한 도구이며 우리가 유용한 멀티쓰레드의 효과를 얻기 위해 사용하는 큐(queue)나 세마포어(semaphore)와 같은 저수준의 프레임워크를 제공합니다.


동기와 비동기

GCD는 큐(queue)는 처리할 부분에 대해 처리를 등록하여 알맞은 스레드에서 처리되는 것이지만 큐에 등록시 다음 실행방식 하나를 지정할 수 있다.
 - 동기화
큐에 처리를 등록한 스레드가 등록한 처리가 완료될때까지 대기
GCD메소드는 sync~
 - 비동기
큐에 처리를 등록한 스레드가 등록한 처리가 완료될 때까지 기다리지 않음
GCD메소드는 async~

차이점은 처리가 완료될 때까지 기다리냐 아니냐의 차이이다. 사실 실무적으로 sync는 사용방법을 잘못하면 스레드 교착상태에 빠질 수 있어 되도록 async를 사용하는 것을 추천한다.


큐 종류

Serial : 
처리를 직렬로 실행한다. 큐의 이전작업이 완료된 후, 다음작업을 시작한다. 한번에 수행할 작업은 하나뿐이다.

let SerialQueue = DispatchQueue(label:"queuename")

Concurrent :
처리를 병렬로 실행한다. 처리가 대기열에서 제거되는 순서는 FIFO이지만 한번에 여러작업을 실행하고 처리가 완료되는 차례도 제멋대로이다.

let ConcurrentQueue = DispatchQueue(label:"queuename", attributes : .concurrent)


*Swift3에서 기본으로 Serial를 사용하고 attributes값을 사용해서 Concurrent 로 만든다.

Main Queue 와 Global Queue

Main Queue
큐 중에서도 앱 시작시 시스템에 의해 자동으로 만들어지는 메인큐라는 별도의 큐가 있다. 이는 대기열에서 등록된 작업은 메인스레드에서 직렬로 실행된다. 이는 별도의 Serial queue라고 말할 수 있다.

DispatchQueue(label: "main").async {
  // async task
  DispatchQueue.main.async {
    print("main")
  }
}


DispatchQueue.main.async 통해 메인큐에서 작업 수행
이때 생성되는 것은 Serial queue인데 Concurrent queue를 생성하려면 아래와 같이 옵션을 지정한다.

DispatchQueue(label: "main", attributes: .concurrent)

Global Queue
글로벌큐는 큐 중에서도 특이점이 있는데, 글로벌 큐는 작업이 들어오면 즉시 스레드를 생성해서 처리한다. 들어오는 만큼 작업을 무한대로 멀티스레딩 한다는 의미이다. 하지만 다른 큐들은 한 번에 하나씩만 작업을 처리한다.

DispatchQueue.global(qos: .default).async {
  print("global")
}


DispatchQueue.global에서 얻을 수 있는 큐는 시스템에서 준비된 Concurrent queue이다. 인수로 지정한 qos(Quality of service)는 우선순위를 결정해준다. 여기서는 default로 지정했지만 우선순위가 높은 것부터 순서대로 아래와 같이 제공되고 있다.

userInteractive
: 유저 사용성을 위해 즉시 수행되는 타입.
UI갱신, 사용자 이벤트 처리 , 애니메이션 등에 사용

userInitiated
: 비동기 UI queue에서 수행되지만, 시스템의 다른 작업들보다 우선순위가 높게 수행된다.
일단 시작되면 끝나기 전에 다른 작업이 중간에 다시 시작될 일은 거의 없다. 빠르게 수행될 수 있고,
UI 상호 작용을 해야 하는 경우에 사용

default
:시스템에서 제공하는 Qos class 타입을 따르기 위해 사용하는 것으로 다른 qos 와 구분을 위해 정의된 것은 아니다.

utility
: 지속적인 작업이 필요할때 사용할 타입이다. 시스템에서 비교적 높은 레벨로 수행된다.
에너지 효율적으로 동작한다고 한다

background

: 시간에 민감하지 않은 작업들을 수행할때 사용된다. 언제 수행될지는 GCD가 컨트롤 한다.

unspecified


출처 : https://brunch.co.kr/@tilltue/29



특정시간 후 작업 수행

아래는 10초후 어떤 작업을 실행하는 예로 DispatchTime.now()에서 얻은 현재 시간에서 .seconds(10)을 통해 10초를 추가했다. seconds는 DispatchTimeInterval이라는 enum이며 다른 값으로는 miliseconds(밀리초), microseconds(마이크로초), nanoseconds(나노초)등으로 지정할 수 있다.

DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .seconds(10)) {
  print("time")
}


Grouping

우선 그룹과 큐를 생성하고 큐에 처리를 등록할 때 그룹을 지정해서 큐와 그룹을 묶는다. 모든 큐 처리가 완료되면 메인스레드에서 처리된다.

//  dispatch 그룹 생성
let g = DispatchGroup()

let queue1 = DispatchQueue(label: "task1")
let queue2 = DispatchQueue(label: "task2")
let queue3 = DispatchQueue(label: "task3")

// 그룹에 포함 시키기
q1.async(group: g) {
  print("queue1 완료")
}
q2.async(group: g) {
  print("queue2 완료")
}
q3.async(group: g) {
  print("queue3 완료")
}
// 모든 queue 가 수행 된 뒤 g.notify 실행
g.notify(queue: DispatchQueue.main) {
  print("전체 작업완료")
}


DispatchWorkItem을 사용하여 작업실행

Swift 3에서 추가된 객체이다.
DispatchWorkItem은 작업을 캡슐화하는 클래스로 다음과 같이 큐 지정이 필수가 아니다. 이 경우 현재 컨텍스트(스레드)에서 처리된다. (실행을 컨트롤 할 수 있다.)

let wi = DispatchWorkItem {
 print("item")
}
wi.perform()


아래와 같이 큐를 지정도 할 수 있다.

q1.async(execute: wi)


이 DispatchWorkItem을 사용하면 처리 실행 perform()외에도 대기 wait() 및 취소 cancel()등 작업에 대한 제어를 세밀하게 할 수 있다. 그외 DisapatchWorkItemFlags옵션도 있어 QoS에 대한 상세한 실행도 가능하다.
중요한 것은 Objective-C언어에서 싱글톤 패턴을 구현하는데 사용하던 dispatch_once는 Swift 3.0에서는 사용할 수 없게 되었다. 또한 dispatch_once_t도 사용할 수 없게 되었다는 것을 기억하자.

Swift 3.0기반 싱글톤 패턴 구현


dispatch_once를 사용못하게 됨에 따라 Swift 3.0부터는 static let속성에서 제공된다. 이 말은 final에서 상속을 금지하고 이니셜라이저를 private하게 되어 자유롭게 인스턴스 생성을 금지하고 static let을 공개한 속성을 통해서만 유일한 인스턴스에 접근할 수 있다.


final class ClassSample {
  static let sharedInstance = ClassSample()

    private init() {

  }
}

출처 : https://swifter.kr/2016/10/22/swift-3-0%EA%B8%B0%EB%B0%98-gcd-%EA%B8%B0%EC%B4%88/





2017년 7월 12일 수요일

WWDC 2017 샘플코드 한번에 받기



터미널 실행 gem 을 설치 하고 아래 명령어 입력 (둘중하나)

$ gem install wwdcdownloader

$ sudo gem install wwdcdownloader



다운로드할 디렉토리를 지정하거나 해당 디렉토리로 이동후  wwdcdownloader 명령입력


$ wwdcdownloader [타겟디렉토리]



2017년 7월 11일 화요일

CFBundleVersion Mismatch - The CFBundleVersion value '1' of extension.. 이슈

앱을 아카이브로 생성 후 업로드 시 발생 할 수 있는 오류
익스텐션을 추가하여 작업하였을 경우 앱의 번들  빌드 버젼과 익스텐션의 빌드 버젼이 다를 시
나타나는 오류로 

아카이브 생성전에
앱의 번들버전과 = 익스텐션의 번들버전
앱의 빌드버전 = 익스텐션의 빌드버전

같도록 해야하다



2017년 6월 22일 목요일

UITextView & UITextField Return button (keyboard 닫기) @@ in Swift3 - Xcode 8.2 iOS 10

UITextView & UITextField  에서 텍스트를 쓰고난 후 키보드를 사라지게 하는 방법
둘다 방법은 같다


 UITextView

1) UITextViewDelegate 추가


class DetailViewController: UIViewController, UITextViewDelegate {
               ...
}

2) UITextViewDelegate  상속 받기

@IBOutlet weak var story_textView: UITextView!

override func viewDidLoad() {
  super.viewDidLoad()

  story_textView.delegate = self
}

3) 함수 추가

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
  if (text == "\n") {
    textView.resignFirstResponder()
  } else {
  }
  return true

4) 스토리보드 내 TextView 의 설정 값에서 리턴키 값을  Done 로 변경



UITextField



1) UITextFieldDelegate 추가

class DetailViewController: UIViewController,  UITextFieldDelegate {
...

}

2) UITextViewDelegate  상속 받기

@IBOutlet weak var story_textfield: UITextField!

override func viewDidLoad() {
  super.viewDidLoad()

  story_textfield.delegate = self
}

3) 함수 추가

func textFieldShouldReturn(_ textField: UITextField) -> Bool {

textField.resignFirstResponder()

return true

}

4) 스토리보드 내 TextField 의 설정 값에서 리턴키 값을  Done 로 변경


2017년 6월 8일 목요일

앱 리뷰창 띄우는 SKStorereViewController 사용 @@ in Swift3 - Xcode 8.2 iOS 10.3

SKStorereViewController 는 iOS10.3 이상버전에서 작동하며 앱리뷰창을 띄워 사용자가 쉽게 앱스토어에 리뷰를 남길수 있습니다.

SKStorereViewController 사용

1.  StoreKit 추가
  import StoreKit

2. 함수 호출 
  SKStoreReviewController.requestReview()

*사용자 입력에 대한 응답으로 호출 해서는 안됩니다

사용의 예 ) 
UserDefaults.standard 를 사용하여 앱 시작시 앱 실행 횟수에 대한 숫자를 세어 5번실행했을때   SKStoreReviewController.requestReview() 를 호출하여 앱 리뷰창이 뜨도록 합니다.

if #available(iOS 10.3, *) { 
 SKStoreReviewController.requestReview()
 } else {
 // Fallback on earlier versions 
 // Try any other 3rd party or manual method here. 
 }

2017년 5월 15일 월요일

Xcode "no suitable image found" 이슈 해결

Reason: no suitable image found.  Did find:

    /Users/name/Documents/proj-name: required code signature missing for '/Users/name/Documents/proj-name/Frameworks/Project.framework/Project'

...



디버깅중에 위 같은 이유로 이슈가 발생한다면 
아래 방법으로 해결이 될 수 있다 (원인이 다를 수 있으므로)
CMD+Option+Shift+K 

2017년 5월 10일 수요일

CocoaPods 설치 후 cannot load underlying module for .. 이슈 해결

제대로 설치 과정을 걸쳤음에도 간혹 cannot load underlying module for... 에러가 발생한다면
아래 방법으로 해결을 시도해 보자
1. 새 프로젝트를 만들고 포드를 설치하지 않고 빌드 및 실행
2. 새 프로젝트에 포드를 설치 후 다시 빌드 및 실행

필자의 실패 사례 : 새 프로젝트 생성 - >  cocoapods 통해 설치 -> 새 프로젝트 열기 -> viewcontroller 에 import 포드 코드 추가 ->  cannot load underlying module for...에러 발생  
필자의 성공 사례 -> 새 프로젝트 -> 빌드 및 실행 -> cocoapods를 통해 설치 -> 새 프로젝트 열기 -> viewcontroller 에 import 포드 코드 추가 (cannot load underlying module for...에러 발생 표시 뜸)-> 빌드 및 실행 -> cannot load underlying module for...에러 사라짐

2017년 4월 12일 수요일

itunes connect 앱 내 결제 기능 적용 시 알아두면 좋은 팁

1. itunesconnect 의 미리 작성을 해야 한다.

앱에서 인 앱 결제 테스트를 진행할 시 앱 상품에 대한 데이터를 못가져오는 경우가 발생하는 이유는
(itunesconnect 의 Contact Info, Bank Info, Tax Info) 정보가 작성되어 있지 않을 경우입니다.
모든 정보를 입력하고 서명을 해야만 제대로 인 앱 결제 테스트가 됩니다.
만일 정보를 입력하지 않은상태에서 인 앱 결제기능을 넣고 심사를 맡길경우
심사에서 "결제 상품 버튼을 클릭했는데 작동하지 않는다"
라는 멘트와 함께 심사 거부가 될 수 있습니다.

<아래 이미지 참조>

2. itunes connect에서 앱 내구입 메뉴에 상품을 등록하는데 이것 또한 심사가 필요하다


3. "개발자가 판매를 거부함" 이라는 상태글이 나올 경우

판매용으로 승인됨 이항목을 체크 안해서 그럽니다. 꼭 체크하세요
심사가 승인 되었음에도 저 항목이 체크 되어 있지 않으면 앱에서 결제창 뜨지 않습니다.
체크하셔야 결제창이 뜹니다 (체크후 8시간 정도 지나니 결제창이 뜨더군요)












4. "개발자의 조치가 필요함" 이건 표시이름의 문제입니다. 다른거 만지지 마세요

심사를 하고 나서 간혹 거부 사유가 "개발자의 조치가 필요함"이라고 뜨는 경우가 있는데
이는 상품의 *표시 이름 에 문제가 있어서 그런듯 합니다. 수정해서 다시 심사하세요

2017년 4월 7일 금요일

구조체와 클래스(struct & class) @@ in Swift3.0


구조체와 클래스


1 - 1 구조체 선언

구조체 이름은 CamelCase 멤버이름은 cameBack 방식으로 지정

struct Person {

  var name : String

  var age : Int

}

1 - 2 새로운 구조체 변수 선언

새로운 구조체 변수를 선언하는 방법은 일반 변수와 동일

구조체 멤버의 값을 읽거나 할당하기 전에 반드시 유효한 값으로 초기화 해야한다.

그러므로 선언과 동시에 초기화하거나 멤버를 선언할 때 기본값을 지정

  var someone = Person(name : "mary", age: 0)

  print(someone.name)
  print(someone.age)

  someone.name = "John"
  someone.age = 3 

* 멤버 값 변경하려면 구조체를 var 로 선언 let 으로 선언 시 읽을 수 있지만 변경 시 컴파일러 오류 발생





2 - 1 클래스

클래스는 선언과 구현이 분리되어 있지 않다. Java, C# 와 동일한 방식으로 하나의 파일에서 클래스를 구현

동일한 모듈에 있는 클래스를 자동으로 인식할 수 있으므로 파일을 임포트할 필요가 없다

만일 다른 모듈에 있는 클래스를 사용하려면 해당 모듈을 임포트 하여야 한다.




2 - 2 클래스 선언

클래스는 class 키워드로 선언

class 클래스이름 : 상위 클래스 이름 {

  속성목록

  메소드 목록

}

* 상위 클래스 이름 생략 가능, 상위 클래스 가 없는 클래스는 다른 클래스의 상위 클래스 역할을 수행하는 기초 클래스가 된다.


class Person {
 
  var name = ""

  var age = 0

  func say () {

    print("Hello \(name)")

  }
}

2 - 3 클래스 초기화

클래스는 생성자를 직접 구현하지 않을 경우 파라미터가 없는 기본 생성자를 자동으로 생성한다.

앞에서 구현한 Person 클래스도 생성자를 구현하지 않았기 때문에 기본생성자가 자동으로 생성된다

새로운 Person 인스턴스는 다음과 같은 생성자 문법으로 생성할 수 있다.

let p = Person()

예)

struct Resolution{
   var width = 10
   var height = 10
}

class Person {
   // 구조체를 파라미터로 사용 가능 
  var someone =  Resolution()

  var name = ""

  var age = 0

  func say () {

    print("Hello \(name)")

  }
}

let viewMode = Person()

print (viewMode.name)
print (viewMode.age)
print (viewMode. someone.height) //  10



* 인스턴스

인스턴스 = 선언한 클래스나 구조체를 가지고 실제 값을 만드는것

설계도로 만든 건물 = 인스턴스
설계도 = 클래스, 구조체




3. 구조체와 클래스의 차이

구조체 =  복사된 종이

struct Resolution{
   var width = 10
   var height = 10
}

var someone =  Resolution()

var otherSomeonesomeone
otherSomeone.height = 20


someone.height    // 10
otherSomeone.height   //20

*  복사된 종이의 값만 바뀌기 때문에 원본은 바뀌지 않음


클래스 = 별명

별명이 수십 수백개여도 결국 이름은 하나

class Person {

  var name = "testname"

  var age = 3

}

let someone = Person()
someone.name = "mary"
someone.age = 30

let otherSomeone = someone
otherSomeone.age = 40

someone.age     // 40
otherSomeone.age   //40






2017년 3월 24일 금요일

UIButton text & textColor 변경 @@ in Swift3 - Xcode 8.2 iOS 10

UIButton 텍스트 변경 및 텍스트 컬러 변경


 -  UIButton 텍스트 변경

editButton.setTitle("test", for: .normal) 

 -  UIButton 텍스트 컬러 변경

editButton.setTitleColor(.clear, for: .normal)

 -  UIButton 백그라운드 컬러 변경

editButton.backgroundColor = UIColor.red

2017년 3월 13일 월요일

Data Type : 튜플 (Tuple) @@ Swift3.0

튜플 (Touple)은 스위프트에서 제공하는 특별한 집단 자료형입니다.

튜플의 특징

1. 튜플은 타입 이름이 따로 없으며 일정 타입의 나열만으로 튜플 타입을 생성 할 수 있습니다.

2.  한가지 타입만 저장할 수 있는 배열이나 딕셔너리와는 달리 하나의 튜플에 여러가지 타입의 요소들을 저장 할 수 있습니다.

3. 일단 선언된 튜플은 상수적 성격을 띠어 최초에 선언된 이후로 값을 추가, 삭제가 불가능 합니다.

4. 튜플에 포함 되는 데이터의 개수는 자유롭게 정할 수 있습니다.

튜플 기본

 - 기본 선언 -
(튜플 요소1, 튜플요소2, ...)
var tupleValue = ("a", 0, true)


 - 타입어노테이션을 이용한 튜플 선언 -
var tupleValue : (String, Int, Bool) = ("a", 0, true)
* 타입 어노테이션을 이용하여 튜플 선언 시 들어갈 요소의 개수와 순서에 맞게 각각 타입을 선언 해야 합니다.


 - 인덱스를 통해 값에 접근 -
print(tupleValue.0)   //  "a"
print(tupleValue.1)    //   0


- 인덱스를 통해 값 할당 -
tupleValue.0 = "insertData"
tupleValue.1 = 100

print(tupleValue.0)   //  "insertData"
print(tupleValue.1)    //   100

튜플 요소 이름 지정

- 튜플 요소 이름 지정 - 
var tupleValue : (name : String, age : Int, data : Bool) = ("a", 0, true)

- 튜플 요소 이름을 통해 값 접근 - 
print(tupleValue. name)   //  "a"
print(tupleValue. age)    //   0
* 인덱스 접근도 가능
print(tupleValue.0)   //  "a"
print(tupleValue.1)    //   0

- 튜플 요소 이름을 통해 값 할당 - 
tupleValue.name = "won"
tupleValue.age = 32

print(tupleValue.name)   //  "won"
print(tupleValue.age)    //   32


튜플 별칭 사용

* 타입 별칭
스위프트에서 기본으로 제공하는 타입이든, 사용자가 임의로 만든 데이터 타입이든 이미 존재하는 데이터 타입에 임의로 다른 이름(별칭)을 부여하여 사용할 수 있습니다.

typealias myInt = Int

typealias personTuple =  (name : String, age : Int, data : Bool)

let tester : personTuple = ("won", 32, true)

print(tester.name)  // "won"
print(tester.age)  // 32






2017년 3월 7일 화요일

App name chage ( 앱 이름 변경) @@ in Swift3 - Xcode 8.2 iOS 10

 App 이름 변경은 간단하다.
Xcode 의 project > Info 를 열어보면 아래 이미지 처럼 "Bundle display name" 항목이 있다
거기에 변경할 앱 이름을 넣어주면 된다.



2017년 2월 20일 월요일

UIImagePickerController 를 이용한 Photo Library 사진 로드 @@ in Swift3 - Xcode 8.2 iOS 10

!!중요
info.plist 에서 Privacy - Photo Library Usage Description  키값을 추가하여 Value 값에 글을 넣어야 합니다. 이작업 없이 진행할 경우 무조건 디버깅중에 아래 글 뜨면서 오류 발생


The app's Info.plist must ... key with a string value explaining to the user how the app uses this data.

<참조>
https://swifteyes.blogspot.kr/2016/11/photolibrary-in-swift3-xcode-80-ios-10.html


1. Delegate 추가
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

2. imageView, View  아울레 추가
 //불러온 사진이 들아갈 뷰
@IBOutlet weak var profileImage: UIImageView!
// 터치하여 Photo Library 를 호출
@IBOutlet weak var profileView: UIView
// UIImagePickerController
let ProfileimagePicker = UIImagePickerController()


3. viewDidLoad() 에 Photo Library 를 호출할 뷰에 터치 액션 넣기
override func viewDidLoad() {
  super.viewDidLoad()

// profileView 를 터치하면  photoAddAction() 가 호출된다
let photoAddAction = UITapGestureRecognizer(target: self, action: #selector(self.photoAddAction(_:)))
self.profileView.addGestureRecognizer(photoAddAction)


4. photoAddAction(_ sender: AnyObject) 에 코드 넣기
func photoAddAction(_ sender: AnyObject){
//포토라이브러리 지원여부
  if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.savedPhotosAlbum){

    //에디팅 여부 true 경우 사진을 에디팅 할 수 있는 뷰 나타남, 에디팅 없이 사진 불러오거나  자신이 만든 에디팅뷰 사용할 경우 false로 설정
    ProfileimagePicker.allowsEditing = true
    // camera, Save photoalbum, PhotoLibrary 중 타입 선택

    ProfileimagePicker.sourceType = .photoLibrary
  self.present(ProfileimagePicker, animated: true, completion: nil)
  }else{
    //"사진라이브러리 접근 할 수 없음" 알럿 뷰
    let alertController = UIAlertController(title: "test", message:
    "Can not access the photo library", preferredStyle: UIAlertControllerStyle.alert)
    alertController.addAction(UIAlertAction(title: "Check", style: UIAlertActionStyle.default,handler: nil))
    self.present(alertController, animated: true, completion: nil)
  }
}


4. 에디팅 된 사진 가져오기
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
  var newImage: UIImage
  if let possibleImage = info["UIImagePickerControllerEditedImage"] as? UIImage {
    newImage = possibleImage
  } else if let possibleImage = info["UIImagePickerControllerOriginalImage"] as? UIImage {
    newImage = possibleImage
  } else {
    return
  }
//에디팅 후 가져온 사진 이미지뷰에 넣기
  profileImage.image = newImage
  self.dismiss(animated: true, completion: nil)
/*
자신이 만든 에디팅 뷰로 사진을 가져가고 싶다면 아래코드 참조
// 자신이 만든 에디팅 뷰컨트롤러 로드
let uvc = self.storyboard!.instantiateViewController(withIdentifier: "CustomimageView") as! CustomPhotoViewController 
// 뷰넘어가는 퍼포먼스 (없어도됨)
uvc.modalTransitionStyle = UIModalTransitionStyle.coverVertical 
// 커스텀 뷰 컨트롤러의 이미지 뷰에 사진 넣기
uvc.Cropimage = newImage 
self.present(uvc, animated: true, completion: nil)
*/
}

// 포토라이브러리 Cancel 버튼 클릭 시
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
  self.dismiss(animated: true, completion: nil)
}

2017년 2월 15일 수요일

CGRectMake, CGPointMake, CGSizeMake, CGRectZero, CGPointZero Swift3문법으로 사용 @@ in Swift3 - Xcode 8.2 iOS 10

Swift2 에서 사용되던 CGRectMake, CGPointMake, CGSizeMake, CGRectZero, CGPointZero가 Swift3에선 바뀌었다.



CGRect(x: Int, y: Int, width: Int, height: Int
CGVector(dx: Int, dy: Int
CGPoint(x: Double, y: Double
CGSize(width: Int, height: Int)


Example:

let newPoint = stackMid.convert(CGPoint(x: -10, y: 10), to: self)
self.physicsWorld.gravity = CGVector(dx: 0, dy: gravity)
hero.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 16, height: 18))
let back = SKShapeNode(rect: CGRect(x: 0-120, y: 1024-200-30, width: 240, height: 140), cornerRadius: 20)


더 자세한 내용은 아래 참조

추천 게시물

애플 개발자 등록방법 2016년 5월 8일 기준!!

애플 개발자 등록 절차 1. 개발자 등록 페이지 이동    애플 개발자 로그인 > Account 페이지 이동 > 하단 영역 클릭 (이미지 참조)   >> Enroll 클릭 >> 무조건 승인!! ...