배열
var arrays : [타입] = []
var arrays = [타입]()
var arrays : Array<타입> = []
var arrays = [ 값, 값, 값 ]
var arrays = [타입]( repeating:반복할요소, count: 반복횟수 )
값추가
arrays.append( 값 )
arrays += [ 값 ]
배열에서 다양한 타입의 값이 저장되어야 하는 경우 타입을 Any 로 지정
Enum
c언어처럼 int 가 할당되는 것이아닌 항목자체가 값이다
enum TypeName {
case one
case two
}
let value:TypeName = .one
let value = TypeName.one
특정 값으로 할당
enum TypeName : String {
case value1 // 값을 할당하지 않으면 타입에 따라 "value1"로 할당됨
case value2="Value2"
}
프로퍼티
getter, setter
getter, setter를 위한 프로퍼티는 Computed Property 이며, 실제값이 저장되는 Stored Property 에서 값을 설정하거나 읽기위한 프로퍼티이다.
class Test {
var _myProperty:Int = 0
var myProperty: Int {
get { return _myProperty }
set { _myProperty = newValue }
}
}
읽기만 가능할 경우 get 생략 가능.
var myProperty: Int { return _myProperty }
프로퍼티 옵저버
실제값의 변경여부를 판단하므로 Stored property만 적용 가능.
생성자에서 초기화될때는 willSet, didSet 함수가 호출되지 않음
class Test {
var myProperty: Int = 0 {
willSet( newValue ) { }
didSet( oldValue ) { }
}
}
lazy Stored Property
해당 프로퍼티에 처음 접근할때 초기화되는 프로퍼티
사용하는 시점에 할당되므로, 내부 멤버에대해 self 접근이 가능하고, 다른 멤버가 할당된 이후에 값을 지정이 가능하므로 불필요한 할당 코드가 줄어들게 된다.
Optional Binding
if let, if var 을 통한 nil 체크와 함께 변수에 값 할당
해당 변수는 if 블록내로 스코프가 제한됨
{
if let 변수 = Optional변수 {
// 할당됨
} else {
// 할당되지 않음
}
}
guard else
조건이 false 이면 else 구문이 실행되며, guard let 변수는 상위 스코프까지 사용 가능하다.
{
guard let 변수 = Optional변수 else {
// 할당되지 않음
// return, throw 등이 없을 경우 컴파일 에러 발생(assert)
}
// 할당됨
}
초기화 제한
init함수에 ?(옵셔널)을 붙이게 되면 Failable Initialize(실패가능한 초기화)로 지정되며, 조건에 의해 실패할 시 nil 을 반환하도록 구성이 가능하다.
init?( value : Int ) {
guard value > 0 else {
return nil
}
self.value = value;
}
클로저
var closure = { header in body }
타입 : ( 인자 목록 ) -> 리턴타입
구현 :
{ ( 인자 목록 ) -> 리턴타입 in
실행 코드 블럭
}
클로저 선언으로 타입을 이미 알고 있으므로, 구현시 인자타입과 리턴타입은 생략 가능하다.
var closure : ( String )->Int
closure = { name in return 0 }
인자와 리턴값이 없는 클로저 ()->Void 의 경우 코드 블록만 작성 가능
var closure : ()->Void
closure = { print("Hello World") }
마지막 인자로 클로저를 사용하는 경우 괄호밖에서 작성 가능
인자가 클로저 하나인 경우 괄호 생략 가능
func test( label value: ()->Void ) {}
test( { 클로저 블럭 })
test() { 클로저 블럭 }
test{ 클로저 블럭 }
프로토콜
다른 언어의 인터페이스, 추상 클래스와 비슷
메쏘드 , 프로퍼티 등 상속받은 측에서 구현해야하는 항목들의 구현 요구사항을 기술
protocol MyProtocol {
// 초기화 명세
init( 인자 )
// 프로퍼티 명세
var value1 : Int { get }
var value2 : Int { get set }
// 함수 명세, class를 붙이면 클래스 메쏘드
func myFunction() -> Void
class func myStaticFunction()
// optional 은 필수로 구현해야 하지 않은 항목
optional public func testFunction()
}
Extension
기존 클래스나 구조체, 프로토콜의 기능을 확장할 때 사용한다.
새로운 기능의 추가만 가능하고, 기존 기능을 오버라이드는 불가능하다.
extention NewExtType : BaseProtocol1, BaseProtocol2 {
func protocolFunction() {
}
}
Codable을 사용한 JSON 처리
codable은 swift4에 추가된 데이터 변환을 위한 타입 프로토콜
Codable을 상속받으면 변수명을 키값으로 자동 치환해 준다.
값으로 별도의 enum 타입을 사용하는 경우에도 Codable을 상속받으면
해당 이름으로 치환
enum MessageType : String, Codable {
case msg
case noti
}
struct Message: Codable {
let id: String
let msg : String
let type : MessageType
}
=> "id":"value", "msg":"value", "type":"msg"
디코딩
// 문자열을 객체로 디코딩
let jsonString = "{ \"id\": \"kim\", \"msg\": \"test msg\", \"type\": \"msg\" }"
let jsonData = jsonString.data( using: .utf8 )
let decoder = JSONDecoder()
let message = try? decoder.decode( Message.self, for: jsonData)
// 배열의 경우
let arrays = try decoder.decode( [Type].self , from: jsonData )
인코딩
let objData = Message( id: "kim", msg:"test msg", type: .msg )
let encoder = JSONEncoder()
encoder.ouputFormatting = [ .prettyPrinted, .sortedKeys ]
if let jsonData = try? encoder.encode( objData ) {
let jsonString = String( data: jsonData, encoding: .utf8)
}
키 이름 변경
구조체의 변수명이 그대로 키 이름으로 사용되었으나 해당 키 이름도 변경가능하다
enum MessageType : String, Codable {
case msg="message"
case noti="notification"
}
struct Message: Codable {
let id: String
let msg : String
let type : MessageType
enum CodingKeys: String, CodingKey {
case id="id"
case msg="msg"
case type="type"
}
}
디코딩 커스터마이징
디코더는 객체 생성 후 init(from: Decoder) 을 호출하는데, 해당 함수를 구현해 커스터마이징이 가능하다
struct Message: Codable {
let id: String
let msg : String
let type : MessageType
// 디코더, 인코더에서 인식할 키 정의
enum MessageKeys : String, CodingKey {
case id="id"
case msg="msg"
case type="type"
}
// 디코더 : json->오브젝트
init( from decoder: Decoder ) throws {
let values = try decoder.container( keyedBy: MessageKeys.self )
// 디코딩은 해당키에서 값을 찾아 변수에 입력하게 된다
id = try values.decode( String.self, forKey: .id )
msg = try values.decode( String.self, forKey: .msg )
// null 요소의 경우 아래처럼 예외처리 가능
// type = (try values.decodeIfPresent( MessageType.self, forKey: .type ) )?? .ms
}
// 인코더 : 오브젝트->json
func encode( to encoder: Encoder) throws {
var values = encoder.container( keyedBy: MessageKeys.self )
// 해당 값과 키를 사용해 인코딩
values.encode( msg, forKey: .msg )
}
}
GCD
DispatchQueue
제공되는 큐
메인큐 (Serial) : 메인 쓰레드에서 처리되는 큐
전역큐 (Concurrent) : 전체 시스템에 공유되는 큐로 우선순위에 따라 처리되는 큐
종류
Serial : 순차적으로 수행
Concurrent : 병렬로 수행
실행 방식
동기(sync) : 작업이 종료될때까지 대기
비동기(async) : 추가 여부만 확인 후 작업 완료 여부는 보장하지 않음
큐에 작업 넣기
DispatchQueue.main.async( execute: { 메인큐에서 처리할 비동기 작업블럭 } )
클로저 표기에 의해 간단하게
DispatchQueue.global().sync{ 전역 큐에서 처리할 동기 작업블럭 }
DispatchQueue.main.asyncAfter(deadline: .now() + 1 ) { 1초 이후에 메인큐에서 처리할 비동기 작업블럭 }
커스텀 큐
커스텀큐는 기본적으로 Serial 큐
Concurrent큐는 attribues: .concurrent
let queue = DispatchQueue( label: "이름")
queue.async { }
중요 iOS UI 요소
키보드
// 메인뷰 하단에 위치하기 위한 bottom constraint
@IBOutlet weak var textFieldLayoutBottomConstraint: NSLayoutConstraint!
// 키보드 이벤트 등록
NotificationCenter.default.addObserver(
self,
selector: #selector( MyViewController.keyboardWillShow ),
name: UIResponder.keyboardWillShowNotification,
object: nil )
NotificationCenter.default.addObserver(
self,
selector: #selector( MyViewController.keyboardWillHide ),
name: UIResponder.keyboardWillHideNotification,
object: nil )
// 키보드 이벤트 해제
NotificationCenter.default.removeObserver(
self,
name: UIResponder.keyboardWillShowNotification,
object: nil)
NotificationCenter.default.removeObserver(
self,
name: UIResponder.keyboardWillHideNotification,
object: nil)
// 이벤트 핸들러
@objc func keyboardWillShow( notification: NSNotification ) {
changeTextFieldBottomConstraint( notification: notification )
}
@objc func keyboardWillHide( notificaiton: NSNotification ) {
changeTextFieldBottomConstraint( notification: notification )
}
// text filed bottom constraint 변경
func changeTextFieldBottomConstraint( notification:NSNotification ) {
let userInfo = notification.userInfo!
let keyboardAnimationDuration = (userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as! NSNumber).doubleValue
let keyboardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
let convertedFrame = self.view.convert( keyboardFrame from: self.view.window )
let rawAnimationCurve = (userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as! NSNumber).uintValue << 16
let animationCurve = UIView.AnimationOptions( rawValue: UInt( rawAnimationCurve ))
textFieldLayoutBottomConstraint.constant = self.view.bounds.maxY - keyboardFrame.minY
UIView.animate(
withDuration: animationDuration,
delat: 0.0,
options: UIView.AnimationOptions( rawValue: UIView.AnimationOptions.beginFromCurrentState.rawValue|animationCurve.rawValue),
animations: { self.view.layoutIfNeeded() },
completion: nil)
}
NSNotification userInfo 의 키보드 관련 내용
public class let keyboardWillShowNotification: NSNotification.Name
public class let keyboardDidShowNotification: NSNotification.Name
public class let keyboardWillHideNotification: NSNotification.Name
public class let keyboardDidHideNotification: NSNotification.Name
public class let keyboardFrameBeginUserInfoKey: String // NSValue of CGRect
public class let keyboardFrameEndUserInfoKey: String // NSValue of CGRect
public class let keyboardAnimationDurationUserInfoKey: String // NSNumber of double
public class let keyboardAnimationCurveUserInfoKey: String // NSNumber of NSUInteger (UIViewAnimationCurve)
public class let keyboardIsLocalUserInfoKey: String // NSNumber of BOOL
// Like the standard keyboard notifications above, these additional notifications include
// a nil object and begin/end frames of the keyboard in screen coordinates in the userInfo dictionary.
public class let keyboardWillChangeFrameNotification: NSNotification.Name
public class let keyboardDidChangeFrameNotification: NSNotification.Name
'프로그래밍 > iOS,macOS' 카테고리의 다른 글
[iOS] GPUImage (0) | 2019.07.06 |
---|---|
xcodebuild (0) | 2019.06.06 |
CocoaPods 라이브러리 배포 (0) | 2019.05.31 |
[Metal] Compute Function 샘플분석 (0) | 2019.05.27 |
[Metal] MetalKit 플로우 분석 (0) | 2019.05.27 |
swift - objective-c 혼합 사용 (0) | 2019.05.22 |
ios pods google 특이한 에러 (0) | 2017.01.26 |
cocoapods 관련 내용 (0) | 2017.01.10 |
ios 크래시 로그 분석도구 symbolicatecrash 사용하기 (0) | 2016.12.14 |
UITableView , UITextView 동적 크기 변화 및 스크롤 (0) | 2016.11.24 |