swift UIButton, UISlider, UILabel

|

개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.


UIButton, UISlider, UILabel

애플리케이션 화면을 구현할 때 자주 사용하는 UI요소들이다.

UIButton

사용자의 상호작용(터치/탭 등의 이벤트)에 반응해 미리 지정된 코드를 실행하는 컨트롤 요소

버튼 생성의 3단계

  1. 버튼을 생성하고 버튼의 유형을 선택
  2. 버튼을 나타내기 위한 문자(타이틀)을 입력하거나, 이미지를 설정한 뒤 크기를 조정
  3. 버튼에 특정 이벤트가 발생할 때 작동할 하나 이상의 메서드를 연결

버튼과 메서드 연결하는 방법

  1. addTarget(_:action:for:) 메서드 사용
  2. 인터페이스 빌더에서 연결 (@IBAction)

이때 버튼과 연결되는 메서드 형식은 아래와 같다.

func doSomething()
func doSomething(sender: UIButton)
func doSomething(sender: UIButton, forEvent event: UIEvent)

버튼의 상태: default, highlighted, focused, selected, disabled

버튼의 상태는 조합된 상태일 수 있다. 예) [default + highlighted], [selected + disabled] 등등
버튼 생성 시 기본 상태 값은 default이며, 사용자가 버튼과 상호작용을 하면 상태 값이 변하게 된다.

그리고, 프로그래밍 방식 혹은 인터페이스 빌더를 이용해 버튼의 각 상태에 대한 속성을 별도로 지정할 수 있습니다. 만약 별도로 속성을 지정하지 않으면 UIButton 클래스에서 제공하는 기본 동작을 사용하게 된다. 예) disabled 버튼은 일반적으로 흐리게 표시되며 사용자가 탭 해도 highlighted 되지 않는다.

버튼의 프로퍼티 값을 설정하는 방식에는 코드를 이용하는 방법과 스토리보드의 인스팩터를 이용하는 방법이 있다.

enum UIButtonType: 버튼의 유형

버튼의 유형에 따라 버튼의 기본적인 외형과 동작이 달라진다. 처음 버튼을 생성할 때

  1. init(type:) 메서드를 이용 혹은
  2. 인터페이스빌더의 “Attribute Inspector”에서 버튼 유형을 지정할 수 있다

이때 한번 생성된 버튼의 유형은 이후 변경 할 수 없으며, 가장 많이 사용하는 유형은 CustomSystem이지만 필요에 따라 다른 유형(Detail Disclosure, Info Light, Info Dark, Add Contact)를 사용할 수 있다.

  • var titleLabel: UILabel?: 버튼 타이틀 레이블
  • var imageView: UIImageView?: 버튼의 이미지 뷰
  • var tintColor: UIColor!: 버튼 타이틀과 이미지의 틴트 컬러

버튼의 주요 메서드

// 특정 상태의 버튼의 문자열 설정
func setTitle(String?, for: UIControlState)

// 특정 상태의 버튼의 문자열 반환
func title(for: UIControlState) -> String?

// 특정 상태의 버튼 이미지 설정
func setImage(UIImage?, for: UIControlState)

// 특정 상태의 버튼 이미지 반환
func image(for: UIControlState) -> UIImage?

// 특정 상태의 백그라운드 이미지 설정
func setBackgroundImage(UIImage?, for: UIControlState)

// 특정 상태의 백그라운드 이미지 반환
func backgroundImage(for: UIControlState) -> UIImage?

// 특정 상태의 문자열 색상 설정
func setTitleColor(UIColor?, for: UIControlState)

// 특정 상태의 attributed 문자열 설정
func setAttributedTitle(NSAttributedString?, for: UIControlState)

UILabel

한줄 또는 여러줄의 텍스트를 보여주는 뷰로, UIButton등의 컨트롤의 목적을 설명하기 위해 사용하는 경우가 많다.

레이블 생성의 3단계

  1. 레이블을 생성
  2. 레이블이 표시할 문자열을 제공
  3. 레이블의 모양 및 특성을 설정

레이블 주요 프로퍼티

var text: String? // 레이블이 표시할 문자열, 문자열이 모두 동일한 속성(폰트, 색상, 기울임꼴 등)으로 표시됩니다.
// text 프로퍼티에 값을 할당하면 attributedText 프로퍼티에도 똑같은 내용의 문자열이 할당됩니다.

var attributedText: NSAttributedString? :  // 레이블이 표시할 속성 문자열
// NSAttributed 클래스를 사용한 속성 문자열 중 특정 부분의 속성을 변경할 수 있다([예] 일부 글자 색상 변경/일부 글자 폰트 변경)
// attributedText 프로퍼티에 값을 할당하면 text 프로퍼티에도 똑같은 내용의 문자열이 할당

var textColor: UIColor! :  // 문자 색상
var font: UIFont!:  // 문자 폰트

var textAlignment: NSTextAlignment:  // 문자열의 가로 정렬 방식으로 left, right, center, justified, natural 중 하나를 선택

var numberOfLines: Int:  // 문자를 나타내는 최대 라인 수
// 문자열을 모두 표시하는 데 필요한 만큼 행을 사용하려면 0으로 설정, 기본 값은 1
// 설정한 문자열이 최대 라인 수를 초과하면 lineBreakMode 프로퍼티의 값에 따라 적절히 잘라서 표현
adjustsFontSizeToFitWidth  // 프로퍼티를 활용하면 폰트 사이즈를 레이블의 넓이에 따라 자동으로 조절해줌

var baselineAdjustment: UIBaselineAdjustment  // 문자열이 Autoshrink 되었을 때의 수직 정렬 방식

Align Baseline  // 문자가 작아졌을 때 기존 문자열의 기준선에 맞춤
Align Center  // 문자가 작아졌을 때 작아진 문자의 중앙선에 맞춤
None  // 문자가 작아졌을 때 기존 문자열의 위쪽 선에 맞춤

var lineBreakMode: NSLineBreakMode  // 레이블의 경계선을 벗어나는 문자열에 대응하는 방식

Character wrap  // 여러 줄 레이블에 주로 적용되며, 글자 단위로 줄 바꿈을 결정
Word wrap  // 여러 줄 레이블에 주로 적용되며, 단어 단위로 줄 바꿈을 결정

Truncate head  // 한 줄 레이블에 주로 적용되며, 앞쪽 텍스트를 자르고 ...으로 표시
Truncate middle  // 한 줄 레이블에 주로 적용되며, 중간 텍스트를 자르고 ...으로 표시
Truncate tail  // 한 줄 레이블에 주로 적용되며, 끝쪽 텍스트를 자르고 ...으로 표시, 기본 설정 값임

UISlider

연속된 값 중에서 특정 값을 선택하는 데 사용되는 컨트롤

슬라이더 생성의 3단계

  1. 슬라이더를 생성하고, 슬라이더가 나타내는 값의 범위를 지정
  2. 적절한 색상과 이미지를 이용해 슬라이더의 모양을 구성
  3. 하나 이상의 메서드를 슬라이더와 연결

사용자 상호작용에 반응하기
사용자가 슬라이더의 값을 변경하면 슬라이더에 연결된 메서드가 호출되어 원하는 작업이 실행
기본적으로는 사용자가 슬라이더의 Thumb를 이동시키면 연속적으로 이벤트를 호출하지만, isContinous 프로퍼티값을 false로 설정하면 슬라이더의 Thumb에서 손을 떼는 동시에 이벤트를 호출

슬라이더와 메서드 연결하는 방법

  • addTarget(_:action:for:) 메서드 사용
  • 인터페이스 빌더에서 연결 (@IBAction)

슬라이더와 연결하는 메서드 형식

슬라이더의 값을 변경했을 때 필요한 정보에 따라 아래 세 가지 중 한 가지를 선택하여 사용

func doSomething()
func doSomething(sender: UISlider)
func doSomething(sender: UISlider, forEvent event: UIEvent)

슬라이더 주요 프로퍼티

슬라이더의 프로퍼티 값을 설정하는 방식에는 프로그래밍 방식과, 스토리보드의 인스펙터를 이용한 방법이 있다.

  • var minimumValue: Float, var maximumValue: Float: 슬라이더 양끝단의 값
  • var value: Float: 슬라이더의 현재 값
  • var isContinuous: Bool: 슬라이더의 연속적인 값 변화에 따라 이벤트 역시 연속적으로 호출할 것인지의 여부
  • var minimumValueImage: UIImage?, var maximumValueImage: UIImage?: 슬라이더 양끝단의 이미지
  • var thumbTintColor: UIColor?: thumb의 틴트 색상
  • var minimumTrackTintColor: UIColor?, var maximumTrackTintColor: UIColor?: thumb를 기준으로 앞쪽 트랙과 뒤쪽 트랙의 틴트 색상

슬라이더 주요 메서드

//  슬라이더의 현재 값 설정
func setValue(Float, animated: Bool)

//  특정 상태의 minimumTrackImage 반환
func minimumTrackImage(for: UIControlState) -> UIImage?

// 특정 상태의 minimumTrackImage 설정
func setMinimumTrackImage(UIImage?, for: UIControlState)

// 특정 상태의 maximumTrackImage 반환
func maximumTrackImage(for: UIControlState) -> UIImage?

// 특정 상태의 minimumTrackImage 설정
func setMaximumTrackImage(UIImage?, for: UIControlState)

//  특정 상태의 thumbImage 반환
func thumbImage(for: UIControlState) -> UIImage?

//특정 상태의 thumbImage 설정
func setThumbImage(UIImage?, for: UIControlState)

swift 인터페이스 빌더와 객체를 코드와 연결(IBAction)

|

개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.


인터페이스 빌더와 객체를 코드와 연결(IBAction)

인터페이스 빌더에서 생성된 객체에서 발생한 액션을 코드와 연결한다. > 사용자 동작에 상호 작용을 할 수 있도록 한다

즉, 실제 앱에서 터치를 통해 일어나는 반응을 확인하는 작업!

컨트롤 이벤트의 종류

컨트롤 이벤트는 UIControl에 Event라는 타입으로 정의되어 있다. 아래는 컨트롤 객체에 발생할 수 있는 이벤트의 종류!

touchDown

컨트롤을 터치했을 때 발생하는 이벤트 > UIControl.Event.touchDown

touchDownRepeat

컨트롤을 연속 터치 할 때 발생하는 이벤트 > UIControl.Event.touchDownRepeat

touchDragInside

컨트롤 범위 내에서 터치한 영역을 드래그 할 때 발생하는 이벤트 > UIControl.Event.touchDragInside

touchDragOutside

터치 영역이 컨트롤의 바깥쪽에서 드래그 할 때 발생하는 이벤트 > UIControl.Event.touchDragOutside

touchDragEnter

터치 영역이 컨트롤의 일정 영역 바깥쪽으로 나갔다가 다시 들어왔을 때 발생하는 이벤트 > UIControl.Event.touchDragEnter

touchDragExit

터치 영역이 컨트롤의 일정 영역 바깥쪽으로 나갔을 때 발생하는 이벤트 > UIControl.Event.touchDragExit

touchUpInside

컨트롤 영역 안쪽에서 터치 후 뗐을때 발생하는 이벤트 > UIControl.Event.touchUpInside

touchUpOutside

컨트롤 영역 안쪽에서 터치 후 컨트롤 밖에서 뗐을때 이벤트 > UIControl.Event.touchUpOutside

touchCancel

터치를 취소하는 이벤트 (touchUp 이벤트가 발생되지 않음) > UIControl.Event.touchCancel

valueChanged

터치를 드래그 및 다른 방법으로 조작하여 값이 변경되었을때 발생하는 이벤트 > UIControl.Event.valueChanged

primaryActionTriggered

버튼이 눌릴때 발생하는 이벤트 (iOS보다는 tvOS에서 사용) > UIControl.Event.primaryActionTriggered

editingDidBegin

UITextField에서 편집이 시작될 때 호출되는 이벤트 > UIControl.Event.editingDidBegin

editingChanged

UITextField에서 값이 바뀔 때마다 호출되는 이벤트 > UIControl.Event.editingChanged

editingDidEnd

UITextField에서 외부객체와의 상호작용으로 인해 편집이 종료되었을 때 발생하는 이벤트 > UIControl.Event.editingDidEnd

editingDidEndOnExit

UITextField의 편집상태에서 키보드의 return 키를 터치했을 때 발생하는 이벤트 > UIControl.Event.editingDidEndOnExit

allTouchEvents

모든 터치 이벤트 > UIControl.Event.allTouchEvents

allEditingEvents

UITextField에서 편집작업의 이벤트 > UIControl.Event.allEditingEvents

applicationReserved

각각의 애플리케이션에서 프로그래머가 임의로 지정할 수 있는 이벤트 값의 범위 > UIControl.Event.applicationReserved

systemReserved

프레임워크 내에서 사용하는 예약된 이벤트 값의 범위 > UIControl.Event.systemReserved

allEvents

시스템 이벤트를 포함한 모든 이벤트 > UIControl.Event.allEvents

swift 인터페이스 빌더와 객체를 코드와 연결(IBOulet)

|

개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.


인터페이스 빌더와 객체를 코드와 연결(IBOulet)

생성된 인터페이스 빌더의 객체를 코드(프로퍼티)와 연결하는 작업을 해보자.

  1. 버튼을 control을 누른상태에서 원하는 곳에 드래그 > 객체 이름 설정
  2. view control을 누른 뒤 드래그

프로퍼티의 이름 변경

[Refactor] > [Rename]

이 방법으로 하지 않으면 자동으로 변경된 이름으로 객체를 연결해주지 않는다.

swift 기본문법 - 사용자정의 연산자(Custom Operators)

|

개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.


사용자정의 연산자(Custom Operators)

Swift는 사용자가 원하는 동작을 하는 연산자를 생성할 수 있다. 그렇기에 Swift에서 연산자는 부호로 표현하는 함수라고 할 수있다.

연산자의 종류

Swift의 연산자는 총 3 종류로 전위, 중위, 후위로 구성

1.전위 연산자: 연산자가 피연산자 앞에 위치하는 연산자

// 대표적인 예) 논리 부정 연산자
a = !a

2.중위 연산자: 연산자가 두 피연산자 사이에 위치하는 연산자

// 대표적인 예) 기본적인 연산자들
a + b
a += b
a - b

3.후위 연산자: 연산자가 피연산자 뒤에 위치하는 연산자

// 대표적인 예) 옵셔널 관련 연산자
a?
a!

연산자는 /, =, -, +, _, %, <, >, &, |, ^, ?, ~ 를 결합하여 만들 수 있다.

마침표(.)을 이용하여 사용자를 만들수 있지만 연산자 문자 중 맨 처음 문자가 마침표여야 하며 .+.는 사용 가능하지만 +.+와 같이 선언하면 +와 .+연산자 로 나누어 인식하게 된다. 물음표와 느낌표는 연산자에 포함 가능하지만 자체적으로 재정의는 불가능하다.

토큰 =. ->, //, /_, */전위 연산자 <, &, ? 중위 연산자 ? 후위 연산자 >, !, ? 역시 재정의가 불가능

전위 연산자

전위 연산자를 구현하기 위해 prefix라는 키워드를 사용

// 연산자를 구현하기 위해 미리 선언
prefix operator **

// 제곱을 수행하는 연산자를 정의
prefix func ** (num: Int) -> Int{
    return num * num
}
print(**100)
// 10000

위의 연산자를 재정의 하지 않고 기능만 추가하려면 연산자를 선언하지 말고 함수를 overload

//논리 부정 연산자를 String에서도 사용 가능하도록 기능을 추가
prefix func ! (str: String) -> Bool{
    return str.isEmpty()
}
// !을 통해 String의 값이 비었는지 확인 가능
print(!"")
// true

후위 연산자

후위 연산자를 구현하기 위해 postfix라는 키워드를 사용

postfix operator ++
// 전위와 같이 연산자를 구현하기 위해 미리 선언

// 값에 1을 더하는 연산자를 만든다
postfix func ++ (num: Int) -> Int{
    return num + 1
}
print(1++)
// 2

하나의 피연산자에 전위와 후위를 한 줄에 사용하게 되면 후위가 먼저 실행

print(**10++)
// (11) * (11)
// 121

중위 연산자

중위 연산자의 종류는 다양하다. 그렇기에 중위 연산자는 특별히 우선순위를 가지는데, 중위 연산자의 우선순위는 더 높은 우선순위, 더 낮은 우선순위, 결합방향, 할당방향을 명시하며 중위 연산자에 우선순위를 명시하지 않으면 우선순위가 가장 높은 DefalutPrecedence그룹이 할당된다.

infix operator <=
// 연산자를 미리 선언

// 서로의 문자의 수를 비교하는 연산자
func <= (str1: String, str2: String) -> Bool{
    return str1.size <= str2.size
}
print( "hello" <= "nice" )
// false

swift 기본문법 - 중첩타입(Nested types)

|

개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.
참고


중첩타입(Nested types)

열거형(Enum)은 종종 특정 클래스나 구조체 기능을 지원하기 위해 만들어진다.

마찬가지로, 보다 복잡한 타입의 컨텍스트내에서 사용하기 위해, 유틸리티 클래스 및 구조체를 정의하는 것이 편리할 수 있습니다.
이를 달성하기 위해 Swift는 중첩된 타입(Nested Types)을 정의할 수 있는데 즉, 지원하는 타입의 정의내에서 클래스 및 구조체, 열거형을 중첩할 수 있다.

다른 타입에서 타입을 중첩하기 위해서는 타입의 괄호 밖에 정의해야 하며, 타입은 필요한 만큼의 여러 수준으로 중첩할 수 있다.

중첩 타입 사용

BlackjackCard라는 구조체는 블랙잭 게임에서 사용하는 게임 카드로 만들어 정의한다. BalckjackCard 구조체는 Suit와 Rank라는 두가지 열거형 타입을 포함한다.

블랙잭에서는 Ace카드 값이 1또는 11로 이러한 특징은 Values라는 구조체로 표현되며, Rank 열거형 안에 중첩되어 있다.

struct BlackjackCard {  // 구조체 생성

    // nested Suit enumeration
    enum Suit: Character {  // 구조체 내 열거형 생성, case들의 raw value가 Character이기에 ray type설정필수!
        case Spades = "♠", Hearts = "♡", Diamonds = "♢", Clubs = "♣"
    }

    // nested Rank enumeration
    enum Rank: Int {  // 열거형 하나 더 생성
        case Two = 2, Three, Four, Five, Six, Seven, Eight, Nine, Ten
        case Jack, Queen, King, Ace
        struct Values {  // 열거형 안에 구조체 생성(struct ⊂ enum, enum ⊂ struct 이런형식임)
          // Ace는 first, second 두개의 값을 가지고 이외의 카드는 한가지 값만 가진다.
            let first: Int, second: Int?
        }

        // 열거형에서는 저장 프로퍼티는 만들 수 없지만, 연산 프로퍼티는 만들 수 있다는 점 잊지말자
        var values: Values {  // 연산프로퍼티, values라는 방금 만든 Values 구조체 타입의 프로퍼티 정의
            switch self {  // 여기서의 self는 Rank를 의미한다
            case .Ace:  // 각 케이스마다 Values 타입의 인스턴스를 리턴
                return Values(first: 1, second: 11)
            case .Jack, .Queen, .King:
                return Values(first: 10, second: nil)
            default:
            // Rank의 첫번째 case Two부터 2라는 값을 주고 있고, 따라서 나머지 케이스에는 1씩 증가한 값이 할당된다.
            // Three의 rawValue는 3이 된다 >> 리턴하는 Values의 인스턴스가 values에 할당되지 않는다(연산 프로퍼티 특징)
                return Values(first: self.rawValue, second: nil)
                }
        }
    }

    // BlackjackCard properties and methods
    // rank와 suit는 BlackjackCard 구조체의 저장 프로퍼티이다(위에 선언한 Rank, Suit 열거형 타입의)
    let rank: Rank, suit: Suit

    // description또한 BlackjackCard의 연산 프로퍼티
    var description: String {
      // 연산 프로퍼티 내 output 선언(output은 description안에서만 쓸수 있는 지역변수)
        var output = "suit is \(suit.rawValue),"  // suit.rawValue는 Suit열거형에서 나열한 기호들
            output += " value is \(rank.values.first)"  // values의 first값
            if let second = rank.values.second {  // 해당 카드가 ace카드였다면 if let(옵셔널 바인딩)으로 values에 second값 있는지 확인
                output += " or \(second)"  // second값이 있다면 넣어준다
            }
            return output
    }
}

이렇게 비로소 BlackjackCard 구조체를 정리해볼 수 있다. 그럼 진짜 BlackjackCard 구조체의 인스턴스를 생성해보자.

// BlackjackCard 타입의 theAceOfSpades라는 인스턴스 생성
let theAceOfSpades = BlackjackCard(rank: .ace, suit: .spades)  // rank, suit는 BlackjackCard의 저장프로퍼티
print("theAceOfSpades: \(theAceOfSpades.description)")  // output을 리턴해주는 description 연산프로퍼티

// theAceOfSpades: suit is ♠, value is 1 or 11

theAceOfSpades: suit is ♠, value is 1 or 11

Rank와 Suit가 BlackjackCard에 중첩되어 있지만, 타입을 컨텍스트에서 유추할 수 있기에 인스턴스를 초기화하면 case 이름만으로 열거 case를 참조할 수 있게 된다.

Referring to Nested Types

정의 컨텍스트 외부에서 중첩된 타입을 사용하려면, 해당 이름앞에 nested type의 이름을 붙이면 된다.

let heartsSymbol = BlackjackCard.Suit.hearts.rawValue
// heartsSymbol is "♡"

따라서 BlackjackCard라는 인스턴스를 만들지 않고 해당값에 접근하고 싶다면, 위 코드처럼 nested type이름을 붙이면 된다.