스톱 워치 만들기 (1) : https://wiwi-pe.tistory.com/34

스톱워치 만들기 (2) : https://wiwi-pe.tistory.com/35

스톱워치 만들기 (3) : https://wiwi-pe.tistory.com/36

스톱워치 만들기 (4) : https://wiwi-pe.tistory.com/37

스톱워치 만들기 (5) : https://wiwi-pe.tistory.com/38

스톱워치 만들기 (6) : https://wiwi-pe.tistory.com/39

스톱워치 만들기 (7) : https://wiwi-pe.tistory.com/40

스톱워치 만들기 (8) : https://wiwi-pe.tistory.com/41
스톱워치 만들기 (9) : https://wiwi-pe.tistory.com/42

 

iOS 개발 튜토리얼1 - 스톱워치 만들기 (9) 테이블뷰

스톱 워치 만들기 (1) : https://wiwi-pe.tistory.com/34 스톱워치 만들기 (2) : https://wiwi-pe.tistory.com/35 스톱워치 만들기 (3) : https://wiwi-pe.tistory.com/36 스톱워치 만들기 (4) : https://wiwi-pe...

wiwi-pe.tistory.com

 

드디어 대망의 완결편입니다.

어쩌다보니 이제서야 완결편을 쓰고있습니다

 

특히 중요하게 생각했던 9편, 테이블뷰쪽 설명이 너무나 넘기고 대충한게 많아서 안타깝네요.

 

오랜만에 다시 이어쓰려고 하니 뭘 안했는지도 기억이 안납니다...

 

그래서 변경하고싶은 세가지 부분을 변경하고 그만두려합니다

 

첫째

테이블뷰에서의 셀안의 이미지가 원래 하려고했던 앱이 아마도 라이트모드에서는 검은색이미지, 다크모드에서는 하얀색이미지였을겁니다.

아마도요;;

그 색상을 변경할것이고

 

둘째

테이블뷰의 라인이 생각보다 거슬립니다;;

그냥 없애버리죠

 

셋째

테이블뷰안의 셀에대한 특별한 이벤트들이 없습니다

하지만 눌러보면 눌러져요!

기본설정입니다 안눌려지게 할꺼에요

 

 

사실 이미지뷰 색상이 이미 지정되어있으실 분도있습니다;

뭐가 기본인지 이건 언제 했는지 기억안나지만 전 파란색으로 뜨고있으니 설정해줍니다

 

그럼 이미지뷰의 색상을 바꿔봅시다

코드로 변경해도되지만 

전 스토리보드가 더 편합니다.

오래만에 main.storyboard로 들어가봅시다

 

아래 사진처럼 셀의 이미지뷰를 선택한후 어트리뷰트 인스펙터의 창으로 들어간후 

뷰 란의 Background 부분을 해당처럼 Default로(색상없음)

Tint를 Label Color로 해주세요.

 

 

 

라벨컬러로 한것은 사실이게 기본 라벨의 텍스트색상입니다 그래서 라이트모드는 블랙, 다크모드는 화이트로 이미 지정되어있어요

그것과 동일하게 해줍겁니다. 참고로 이러한 색상하나에 두가지 상태를 지정해주는거는 따로 할수있으나 여기선 다루지않았습니다.

 

 

동영상은 볼때 광고들어가서 싫은데 이미지 용량제한이 가슴아프게하네요.

 

아무튼 3가지중 하나가 완료되었습니다.

 

만약 변경이 안되시는분은 이전편에서 Assets.xcassets 에서 이미지 속성 변경한게 제대로 되어있나확인하고

혹시나 이미지 속성에대해 따로 설정을 만진부분이 있는지 특히 코드로요 그부분을 확인해주세요

 

두번째와 세번째는 한번에 처리하죠!

다시 Main.storyboard로 갑니다.

그후 테이블뷰를 선택한후 어트리뷰트 인스펙터창을 엽니다

아래 사진처럼 separator 부분을 None으로

Selection 부분을 No Selection으로 변경해주세요

 

 

 

깔끔하게 됐네요

마지막이 되었으니

이프로젝트 전체를 깃허브에 올린 링크를 첨부합니다 ㅎ

 

https://github.com/wiwi-git/Simple_Stopwatch

 

wiwi-git/Simple_Stopwatch

Tutorial - 1탄! Contribute to wiwi-git/Simple_Stopwatch development by creating an account on GitHub.

github.com

 

* 실수로 프로젝트 파일의 대부분을 날려먹어서, 기존에있는거랑 없어진부분 채우고 하면서 조금 달라졌을수도 있습니다;

 

 

 

 

다들 수고하셨어요~

 

아... 다신 이런짓 하기싫네요.

짧게짧게 쓰기만해야겠습니다........ 너무 길었어 

 

 

 

 

반응형

스톱 워치 만들기 (1) : https://wiwi-pe.tistory.com/34

스톱워치 만들기 (2) : https://wiwi-pe.tistory.com/35

스톱워치 만들기 (3) : https://wiwi-pe.tistory.com/36

스톱워치 만들기 (4) : https://wiwi-pe.tistory.com/37

스톱워치 만들기 (5) : https://wiwi-pe.tistory.com/38

스톱워치 만들기 (6) : https://wiwi-pe.tistory.com/39

 

iOS 개발 튜토리얼1 - 스톱워치 만들기 (6) 스토리보드와 코드 연결하기,함수만들기, 코드로 버튼과 함수 연결하기

스톱 워치 만들기 (1) : https://wiwi-pe.tistory.com/34 스톱워치 만들기 (2) : https://wiwi-pe.tistory.com/35 스톱워치 만들기 (3) : https://wiwi-pe.tistory.com/36 스톱워치 만들기 (4) : https://wiwi-pe...

wiwi-pe.tistory.com

 

 

 

저번편에서 버튼에서 하나 잊은게있었습니다.

 

isEnabled 속성입니다.

 

어제 소스 그대로 시뮬레이터로 돌려보면 버튼중에 startButton을 누르면 콘솔에 10이 뜨고

그외에는 UI적으로 눌렀다는 표시만 나올겁니다.

이 눌렀다는 표현이 나온다는거 자체를 막아야할때가있습니다.

 

그때 쓰는게 바로 isEnabled 속성입니다. 기본은 true로 당연히 모든버튼이 누를수있도록 되어있습니다.

애플문서의 설명은 저번 포스트에서 있을거에요 넘어가겠습니다.

 

스톱워치라하면 startButton을 누르기전까진 랩타임이 기록되면 안되고 스톱버튼도 동작이 무의미하겠죠?

 

오히려 스톱버튼이 불필요한 동작으로인해 다른 문제가 발생할여지도 있습니다.

 

그래서 startButton을 눌러 시작상태가 될때만 이 둘이 동작가능하도록 하겠습니다.

 

우선은 checkButton만 해보죠

 

저번 소스의  viewDIdLoad함수안에 있는 

 

startButton.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)

소스 바로 아래라인에 추가해주세요

 

checkButton.isEnabled = false

 

이제 시뮬레이터로 실행을 시켜보면

 

위 그림처럼 Check 버튼자체가 눌려지지 않게됩니다

 

추가로 stop버튼도 

 

이제 다른 버튼에 대해 기능을 달아주기전에 enum 변수에대해 조금 알아보고갑시다

 

열거형 변수라고 부르는 enum은 

단순히 여러개의 종류를 한묶음으로 묶어줄때 사용합니다.

 

형태는 아래와 같습니다

 

enum 이름 {

    case 첫번째항목

    case 두번째항목

}

 

예시로 하나 들자면

 

enum Icecream {

    case vanilla

    case strawberry

    case cherry

    case chocolate

}

이렇게 아이스크림 종류가 있겠네요.

 

사실 굳이 이걸 안써도 되지만

 

 

swift에서는 이 enum과의 switch의 상성이 매우 좋습니다.

 

위의 아이스크림을 아래와같이 할 수 있어요

 

var selectIce:Icecream 

이렇게 Icecream이라는 enum형식을 가진 selectIce라는 변수가 있다면

 

switch selectIce {

    case .vanilla :

        print("바닐라를 선택하셨습니다.")

    case .strawbrerry :

        print("딸기를 선택하셨습니다.")

    case .cherry :

        print("체리를 선택하셨습니다.")

    case .chocolate :

        print("초콜릿을 선택하셨습니다.")

}

 

이런식으로 모든 switch에서 나올수 있는 항목을 enum으로 지정한 항목만 가능하도록 할 수 있습니다.

물론 다른언어처럼 중간에 선택할 필요없는 항목은 default 라는걸로 생략 할 수 있어요

이번 튜토리얼에서 버튼들의 기능을 하나의 함수로 묶는다고 했는데

바로 이때 쓸겁니다.

버튼 종류를 한정시켜놓고(enum) switch문으로 나눌꺼에요

 

MainVC 클래스 내부 상단에 아래와같이 정의해줍시다

 

    enum ButtonTag:Int {

        case start = 10

        case check = 20

        case stop = 30

        case reset = 40

    }

  

갑자기 각 case에 값이 달렸네요!

네 스위프트에서는 enum의 가능성은 무한한합니다!

 

공부해 나가다보면 함수도 달고 이것저것 달고 마치 하나의 클래스를 지정하듯한 모습을 보실수 있을겁니다만

튜토리얼에서는, 그리고 제가 짜는 코드에서는 값이 달리는것 외에는 없겠네요.

 

아직도 주니어 개발자이고 여태 해본 프로젝트에서는 더이상의 기능은 필요가 없었어요.

 

값을 지정해주려면 enum의 이름 옆에 타입을 적어주고

각 case 에 그 타입에 맞는 값을 넣어주시면 됩니다.

 

추가로 enum에 값을 넣어주시면 그 값에 해당하는 내용이 있는지 검사해볼수 있습니다

 

enum의 이름을 적어서 생성자같이 해주면됩니다!

ButtonTag(rawValue: 찾는값) 이라고 해주면 옵셔녈 변수로 값을반환해줍니다.

 

또 다른 언어에는 없는 변수가 나왔네요.

옵셔녈 변수는 

선언할때는 변수타입뒤에 '?'를 붙여서 선언해줍니다

이는 값이 있을수도 있고 없을수도 있어! 라고 해주는건데

하나의 변수에 값에 대한 지정을 없다 or 값 으로 해줄 수 있어 좀더 안정적인 프로그래밍이 가능해도록 해주는 녀석입니다

이 옵셔널이라는건 일종의 포장입니다 

(원래값을 가진 변수) 를 (옵셔널(원래값을 가진 변수)) 이 되어 

옵셔널을 풀어줘야만 원래값을 볼 수 있습니다

이 원래값을 가진 변수 부분에 사실 값이 없을 수 있을경우( null값, swift에서는 nil이라 부릅니다)

이 옵셔녈을 바로 풀어주면 nil이 나오게 됩니다.

 

옵셔녈을 풀어주는 방법은 여러가지 있는데 여기서 두가지만 소개하자면

b라는 옵셔널 변수가 있다면 이를 사용하기 위해선 

첫번째

if안에서 변수를 선언해서 사용가능합니다.

if let a = b {

    내부에서만 사용가능

}

if의 조건문 자리에 b를 할당하는 변수를 선언하게되면 이 b가 할당가능하면( 옵셔널내부에 값이 존재하면) a라는 변수에  b가 가진 원래값을 넣고 아니라면 else로 빠져나가게 되는 조건문이되겠습니다 

 

두번째

b가 nil일때 대신할 값을 지정 

let a = b ?? c

 옵셔널값의뒤에 물음표 두개를 붙이면

b가 nil일때 c를 a에 대신넣는다 라는게 됩니다.

 

물론 c와 b의 원래값의 타입은 같아야합니다.

 

옵셔널에대한 더 자세한 설명은

https://docs.swift.org/swift-book/LanguageGuide/TheBasics.html

링크에서

Optionals

항목을 찾아 읽어주세요!

 

그리고 enum은

https://docs.swift.org/swift-book/LanguageGuide/Enumerations.html

링크에 더 자세한 설명이 되어있습니다

 

 

 

그럼 잠시 enum은 멈춰두고

 

함수에대해서 이야기 할겁니다.

 

이 튜토리얼의 대상이라면 이미 다른 언어나 혹은 같은 언어로 이미 함수에대해 많이 알고 계실거라 생각됩니다.

 

파이썬이라면

def 함수이름() :

  함수내용

 

자바라면

void 함수이름() {

}

 

그리고 스위프트는(4 이상)

 

func 함수이름() {

}

입니다만 저번편을따라해보신분은 이미 buttonAction함수를 생성하셨을것이고

거기에서 살짝 이야기를 했습니다.

 

좀더 자세히 보자면 함수 형태는 아래와같습니다.

접두사 func 함수이름(파라미터 닉네임 받는 파라미터 : 파라미터 타입) -> 반환타입 {

}

저번포트스에서

@objc func buttonAction(_ sender:UIButotn) {

}

이라고 함수를 하나 만들었는데

@objc가 바로 접두사 쪽( 본래 명칭이 아닐 수 있습니다..;;)

그리고 함수를 뜻하는 func

함수이름은 buttonAction

파라미터는 , 로 구분하는데 하나만 있고

이 파라미터의 닉네임은 _ 로 생략한다.

파라미터명은 sender 이고

파라미터의 타입은 UIButton이다

 

이함수의 반환형은 Void로 없다 없을 경우 저렇게 파라미터위치 옆을 비워둘수있습니다.

 

사실 buttonAction은 이런거죠

    @objc func buttonAction(_ sender:UIButton) -> Void {

        print(sender.tag)

    }

 

 

 

만들 함수는 이전 포스트에서는 버튼에대한 내용을 하나하나

viewDidLoad 함수에서 해줬는데 이에대한 중복을 조금 줄일겁니다.

 

아래와같이 MainVC클래스 내부에 만들어주세요!

 

    func setButton(button:UIButton, tag:ButtonTag){

        button.addTarget(self, action: #selector(buttonAction(_:)), for: .touchUpInside)

        button.tag = tag.rawValue

    }

 

이 setButton이라는 함수는 UIButton과 ButtonTag라는 enum형식 변수를 받아 받은 버튼에대한 속성을 지정해주는 함수입니다

이전

        startButton.tag = 10

        startButton.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)

를 함수로 만들어준거에요

라인 순서만좀 달라졌네요

이제 이 만든 함수를 이용해 버튼들을 완성시켜봅시다

 

viewDidLoad()함수에서 이전에 지정해준 startButton에 대한 내용을 지우고 아래와같이 완성시켜주세요

 

    override func viewDidLoad() {

        super.viewDidLoad()

        setButton(button: startButton, tag: .start)

        setButton(button: checkButton, tag: .check)

        setButton(button: stopButton, tag: .stop)

        setButton(button: resetButton, tag: .reset)
        checkButton.isEnabled = false

    }

 

현재로서는 viewDidLoad함수는 위와같아야합니다

이러게하면 이제 모든 버튼이 buttonAction함수와 연결이 된겁니다.

 

이제 buttonAction함수를 좀 채워줄꺼에요

이전 Print를 적어준건 지우고 아래와같이 작성해줍시다.

    @objc func buttonAction(_ button:UIButton) {

        if let select = ButtonTag(rawValue: button.tag) {

            switch select {

            case .start: startAction()

            case .check: checkAction()

            case .reset: resetAction()

            case .stop : stopAction()

            }

        } else {

            print("존재하지않는 태그를 가진 버튼의 입력이 들어왔습니다.")

        }

    }

 

 

if let select는 위에서 설명했던데로 ButtonTag(rawValue:)의 반환값이 옵셔녈이라 사용해주기위해 쓴겁니다

그리고 내부는 start, check, rest,stop버튼 항목이 각각 연결해준 함수들이있습니다

 

이 함수들은 아직 안만들어줘서 xcode에서 빨간 줄이 그어질겁니다

 

 

이제 이 존재하지않다고 빨간줄 뜨는 함수들을 다 만들어줄꺼에요

MainVC내부에 아래와같이 추가해줍시다

    
    func startAction() {
        print("start")
        startButton.isEnabled = false
        checkButton.isEnabled = true
        stopButton.isEnabled = true
    }
    
    func checkAction() {
        print("check")
    }
    
    func stopAction() {
        print("stop")
        startButton.isEnabled = true
        checkButton.isEnabled = false
        stopButton.isEnabled = false
    }
    
    func resetAction() {
        print("reset")
        startButton.isEnabled = true
        checkButton.isEnabled = false
        stopButton.isEnabled = true
    }

각버튼이 눌리면 무슨버튼인지 콘솔에 출력해줄것이고

 

startAction이 실행되면

기존에 작동을 안하게 해뒀던 check와 앞으로 stop 상태에 들어가면 중지시킬 stop 버튼을 동작하게 해주고

계속해서 startButton이 안눌리도록 startButton의 isEnabled를 false로 설정해줍니다

 

 쭉쭉 이런식으로

stop과 start. 거의 토글식으로 

reset은 전부 처음으로 돌려주고 하는식으로 해줄꺼에요

 

그럼 이제 돌려봅시다

 

 

잘 동작하네요!

 

그럼 다음편에서는 시간이 흐르도록 해봅시다

반응형

스톱 워치 만들기 (1) : https://wiwi-pe.tistory.com/34

스톱워치 만들기 (2) : https://wiwi-pe.tistory.com/35

스톱워치 만들기 (3) : https://wiwi-pe.tistory.com/36

스톱워치 만들기 (4) : https://wiwi-pe.tistory.com/37

스톱워치 만들기 (5) : https://wiwi-pe.tistory.com/38

 

iOS 개발 튜토리얼1 - 스톱워치 만들기 (5) Constant수정, 다크모드 전환

스톱 워치 만들기 (1) : https://wiwi-pe.tistory.com/34 스톱워치 만들기 (2) : https://wiwi-pe.tistory.com/35 스톱워치 만들기 (3) : https://wiwi-pe.tistory.com/36 스톱워치 만들기 (4) : https://wiwi-pe...

wiwi-pe.tistory.com

 

스톱워치 만들기 5까지 끝내셨다면 이제 스토리보드에 오브젝트를 추가할일은 없습니다

이번편부터 주로 다룰 부분은 텍스트창 입니다 확장자가 .swift 로 되는 파일들에 적어넣어갈꺼에요

 

우선 파일 이름이 마음에 안들어서 하나 삭제하고 다시 만들겁니다.

프로젝트 네비게이션에서 ViewController.swift 파일을 선택하고 키보드의 Delete키를 눌르신후 휴지통으로 버려주세요

위 사진의 선택된 부분을 삭제하시면됩니다.

그후 프로젝트 네비게이터의 Tutorial1 라 적힌 폴더에서 마우스 우클릭(옵션메뉴)을 한후 New File을 선택해줍니다

 

아래 사진의 iOS 의 Cocoa Touch Class( 소스 템플릿입니다)를 선택하신후 다음을눌러주세요

 

Class이름을 MainVC라 적을겁니다.

그리고 다음을 누르고 생성을 누르시면됩니다

 

 

굳이 원래있던 ViewController.swift 를 삭제하고 같은 역할을하는 클래스를 생성해준이유는 

그냥 제 스타일입니다 ㅎ 

그냥 원래 있던 ViewController.swift에서 앞으로할 작업을 하셔도 상관없어요

저는 스토리보드이름과 vc(viewcontroller)파일이름을 맞춰주는걸 좋아해서 이렇게 했습니다

저와같이 생성하셨으면

프로젝트 네비게이터가 아래사진과같이 되시면됩니다

 

 

다시 Main.storyboard로 돌아가서

아래 사진의 화면의 아이폰화면 상단에 있는 검은색바를 선택해주세요

 

그후 인스펙터즈 화면에서  네번째 아이콘 아이덴티티 익스펙터화면으로간후

Custom Class가 아래화면처럼 ViewController로 되어있을겁니다 

이는 처음 자동생성되면서 방금 지운 ViewController.swift에 만들어져있는 ViewContoller클래스이름이 자동으로 넣어져있는겁니다

이 Class를 아래와같이 변경해주세요. 방금 만든 MainVC를 적으시면됩니다

 

변경이 잘됐으면 스토리보드의 좌측영역 스트럭쳐에리어 부분이 ViewController Scene에서 MainVC Scene으로 변경되었을겁니다

 

 

다룰 클래스도 바꾸었습니다

이제 스토리보드영역의 상단바의 가장 오른쪽 버튼(Add editor on Right 라 설명이 나오는 버튼)을 눌러 에디터화면을 늘려줍니다 아래 사진의 하얀색 점선으로 그린 사각형 영역입니다 

 

 

이버튼을 누르면 화면이 아래와같이 되었을겁니다

추가된 화면의 상단바의 Main.storyboard라고 적힌 부분을 클릭한후 MainVC를 눌러주세요

각 에디터는 이런식으로 변경해줄수도 있고

프로젝트 네비게이터에서 드래그앤드롭으로 변경해줄수도 잇습니다. 아니면 바꿀에디터화면을 한번 선택한 상태에서 프로젝트 네비게이터에서 열 파일을 선택하시면됩니다.

 

여러방법으로 추가한 에디터화면이 아래 사진과 같이 되었으면됩니다 

위 사진과같이 여셨다면 아래 영상과같이 소스코드에 각 오브젝트들을 연결해주세요

 

 

영상에는 안나왔습니다만 스토리보드에서 아이템을 소스로 연결시킬때는 컨트롤키를 누른상태에서 드래그엔 드롭 해주시면됩니다

 

 

각 소스에 붙은 @IBOutlet 은

@IB는

 Interface Builder Annotation 의 IB와 A를 @로 한거라하는데 자세한 설명이 안보이네요 .

저도 독학으로 공부한거라 미흡한 부분이 많으니 부디 이 튜토리얼을 따라하시는분들은 따로 검색해보시기바랍니다.

스토리보드에서 바로 코드로 연결하는 변수들은 두가지 정도의 종류가 있습니다 

@IBOutlet( 앞으로는 아울렛변수라 부르겠습니다)

@IBAction 

 

아울렛 변수는 그 해당하는 아이템의 속성을 변경해주기위해 지정하는것이고

IBAction은 화면에서는 안나왔지만 버튼과같은 컨트롤오브젝트들의 동작을 바로 함수로 연결해줄때 함수앞에 붙는 이름입니다.

 

아울렛변수로 지정하는것은 스토리보드에서 어트리뷰트 인스펙터보다 더 다양하고 또 프로그램의 흐름에따라 변경이 가능하게할 수 있기에

많이 사용하게 될겁니다.

 

물론 이들은 스토리보드와 같이 개발할때 사용합니다 ㅎ

 

 

 

 

오늘은 버튼하나에 대해서는 다루다 끝을 맺겠습니다

자동으로 생성된 소스에는 

 

override func viewDidLoad() {

        super.viewDidLoad()

        // Do any additional setup after loading the view.

  }

라는 부분이 있습니다.

 

친절하게도 저렇게 주석이 달려있어서 무슨 역할을 하는 함수인지 알아볼수 있어요

view에 대해 아직 익숙하지 않을시점이지만 무엇인지는 짐작이 가실테고 제목에서부터 view가 로드된후 라는이름을 가진 함수라

쉽게 짐작하실겁니다.

 

이 함수는 뷰가 전부다 생성이 된후에 이 클래스가 처음 실행될때  단 한번만 실행이 되는 함수입니다 원래 setup이라는게 보통 한번만 해주잖아요? ㅎ 

 

단 한번만이라는게 중요한데

이 Viewcontroller라는게 여러 주요 돌아가는 함수들이 있습니다.

이에대해 궁굼하신분은 추가적으로 iOS ViewController Life Cycle 라고 검색하시면 더 자세히 알 수 있습니다

 

아무튼 다시 원래 이야기로 돌아가서 이번 포스트에서는 버튼에 대한걸 하나만 이 viewDidLoad함수에다가 설정해주고 끝낼겁니다

 

이 버튼은 UIButton 이라는 클래스입니다

이 클래스는 UIControl이라는 클래스를 상속받은 클래스이고

UIControl은 UIView라는 클래스를 상속받은 클래스입니다.

 

결국다! UI라 붙은 클래스들은 그 상위가 UIView의 민족이라는 놀라운 이야기.........

는 집어치우고 

 

상속받은 클래스들 이름을 보면 알수 있듯이 이 UIButton은 View가 있고 Control을 할 수 있는 클래스입니다.

이 뷰쪽은 스토리보드에서 설정을 끝마쳤으니 저희가 할 부분은 Control부분의 설정입니다,.

 

UIButton에서 사용할 속성과 함수들은( 애플에서의 설명들...)

 

. 애플 도큐먼트 페이지를 보시면 더 많은 정보를 얻으실 수 있으십니다.

 

 

 

 

우선 UIView에 정의되어있는 태그

tag

An integer that you can use to identify view objects in your application.

Declaration

var tag: Int { get set }

Discussion

The default value is 0. You can set the value of this tag and use that value to identify the view later.

 

 

 

 

 

 

UIControl에 정의되어있는 addTarget

addTarget(_:action:for:)

Associates a target object and action method with the control.

Declaration

func addTarget(_ target: Any?, action: Selector, for controlEvents: UIControl.Event)

 

 

 

 

 

UIControl에 정의되어있는 isEnabled

isEnabled

A Boolean value indicating whether the control is enabled.

Declaration

var isEnabled: Bool { get set }

Discussion

Set the value of this property to true to enable the control or false to disable it. An enabled control is capable of responding to user interactions, whereas a disabled control ignores touch events and may draw itself differently. Setting this property to false adds the disabled flag to the control’s state bitmask; enabling the control again removes that flag.

The default value of this property is true for a newly created control. You can set a control’s initial enabled state in your storyboard file.

 

 

UIButton에 대해 설정할 수 있는데 엄청 많지만

이렇게 버튼은 세개만 다룰겁니다.

 

 

우선 startButton에 tag를 지정할겁니다

태그는 일종의 이름으로서 클래스내부에서 startButton이라는 버튼의 주민등록번호같은 역할을합니다

이렇게 태그를 넣어주는이유는 MainVC라는 클래스에서 사용되는 버튼들이 눌려졌을때에대한 동작을 하나의 함수로 몰아주려고하는데

이따 하나의 함수에서 여러개의 버튼을 구분하기위한 방법중하나입니다.

물론 이 버튼에 쓰여있는(버튼 라벨)글이나 여러가지방법으로 구분이 가능할수도 있겟습니다만

저는 태그를 통해 하려고해요

 

소스를 다음과같이 수정해줍시다

 

viewDidLoad()의 주석을 지우고 그자리에 

startButton.tag = 10

을 넣어주세요. ( Tag의 설명에 있듯이 태그값은 정수만 가능합니다 )

 

override func viewDidLoad() {

    super.viewDidLoad()

    startButton.tag = 10

}

 

태그는 지정해주었고 이제 startButton이 눌러졌을때의 기능을 만들겁니다

 

viewDidLoad() 함수가 끝나는 '}' 다음에 

다음과같이 적어주세요

 

@objc func buttonAction(_ sender:UIButton) {

    print(sender.tag)

}

 

@objc 라는의미는 스위프트 이전에 iOS앱만드는데 사용했던언어인 objective C에서 사용된 라이브러리

혹은 각종 클래스에서 사용할 수 있게 만드는 마법의 키워드입니다

 

이 키워드로 인해 swift와 objective c는 좋은 사이를 유지하면서 발전가능해집니다

 

위에서 스토리보드의 오브젝트들과 코드를 연결해주면서 자동으로 연결되었던 라인들을 보시면 짐작하시겠지만

스위프트4에서는 기본적으로 

상수or변수  이름:타입 = 값

형태로 변수를 선언합니다

이 형태는 함수의 파라미터에서도 그대로 사용됩니다.

buttonAction이라는 함수는 sender라는 이름의 파라미터를 가지고있는데

이는 변하지않는 상수 형태이며 UIButton이라는 타입인 파라미터라고 쓴겁니다.

 

sender 앞에 ' _ ' 라고 적은것은

외부에서 함수를 부를때 buttonAction( 값 ) 형태로, 파라미터이름을 표시하기 싫을때 _ 라고 표시합니다.

 

이를 _ 대신 다른, 예를 들어 A라 적었으면 buttonAction(A: 값) 형태로 호출을 해야합니다.

외부에서 보여지는 파라미터의 닉네임을 정해줄수 있는거에요

 

buttonAction은 꼭 파라미터를 _ sender:UIButton 으로 줘주세요 ( 여기 프로젝트에서 한정입니다 ^^) 

 

다른 언어 특히 파이썬을 해보신분은 buttonAction함수안에 있는 내용이 상당히 익숙할건데

이는 sender라는 버튼의 태그값을 콘솔에 출력해주세요 라는 명령입니다.

 

 

 

이제 startButton에 묶을 함수까지 만들었으니

startButton에 함수를 연결해줘야합니다.

 

startButton.tag = 10 라인 밑에

 

startButton.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)

라고 적어줍시다

 

addTarget은 

 

위에 애플설명처럼 

 

타겟 오브젝트와 액션메소드(함수)를 연결시켜주는 UIControl에 정의되어있는 함수입니다 

원형은 

 

func addTarget(_ target: Any?, action: Selector, for controlEvents: UIControl.Event)

인데  타겟 파라미터 앞에 _ 가 붙어있죠?

그래서 startButton에 addTarget의 가장첫파라미터는 target: 값 이라 적지않고

바로 self라는 값을 넣어준겁니다. 

 

이 타겟의 파라미터에 대한 설명을 애플은 아래와같이 문서에 적어놨습니다.

target
The target object—that is, the object whose action method is called. If you specify nil, UIKit searches the responder chain for an object that responds to the specified action message and delivers the message to that object.

 

요약해 호출되는 객체를 지정하는 것이라는데 저는 아직 self 밖에 해보질않아 다른것을 지정해줄때도 있는것인지 모르겠습니다!

혹시 이글을 보시는분들중에 아시는분계시다면 꼭 공유해주셨으면 좋겠네요 

 

그렇게 다음 action은 지정해줄 함수를 말하는데

#selector가 objective c로 만들어진것인지 

액션메소드가 꼭 @objc가 붙어야 인식이됩니다.

그다음은 for 라는 파라미터는 버튼의 상태, 어떤 이벤트가 발생했을때 이 액션메소드(buttonAction)가 실행되는가인데

 

다른 UIControl를 상속하는 오브젝트들의 이벤트까지 같이 들어있기에 꽤 많이 있습니다

우리는 이 많은 이벤트중에 

 

static var touchUpInside: UIControl.Event

A touch-up event in the control where the finger is inside the bounds of the control.

 

를 사용할겁니다

말그대로 버튼을 누른후 그장소에서 손을땠을때 라는이벤트입니다

 

이번에 지정해준 addTarget의 내용을 정리하자면

영어이니 뒤에서부터 해석하자면

버튼을 눌렀다가 그 장소에서 땟을때 buttonAction를 함수를 실행시키는데 이에대한 호출자가 startButton이다 라는 의미입니다.

 

그렇게 

 

class MainVC:UIViewController {} 의 총 소스는

아래와같습니다.

 

import UIKit

class MainVC: UIViewController {
    
    @IBOutlet weak var lapTableView: UITableView!
    
    @IBOutlet weak var timeLabel: UILabel!
    @IBOutlet weak var decimalLabel: UILabel!
    
    @IBOutlet weak var startButton: UIButton!
    @IBOutlet weak var checkButton: UIButton!
    @IBOutlet weak var stopButton: UIButton!
    @IBOutlet weak var resetButton: UIButton!
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        startButton.tag = 10
        startButton.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
    }
    
    @objc func buttonAction(_ sender:UIButton) {
        print(sender.tag)
    }
}

 

이를 시뮬레이터, 아이폰11에서 실행하면 

아래영상과같이 나온다면 성공입니다!

 

 

그럼 다음 포스트에서 봐요~

반응형

스톱 워치 만들기 (1) : https://wiwi-pe.tistory.com/34

스톱워치 만들기 (2) : https://wiwi-pe.tistory.com/35

스톱워치 만들기 (3) : https://wiwi-pe.tistory.com/36

 

iOS 개발 튜토리얼1 - 스톱워치 만들기 (3) 스토리보드 + Label + Button

스톱 워치 만들기 (1) : https://wiwi-pe.tistory.com/34 스톱워치 만들기 (2) : https://wiwi-pe.tistory.com/35 저번 2편까지 무사히 끝내셧다면 앱이 시뮬레이터로 무사히 실행이 되었으나 앱에 아무것도 없었..

wiwi-pe.tistory.com

 

저번 시간까지 무사히 마치고 이번 포스트까지 오셧다는 가정하에 시작해보겠습니다.

이번에는 저번 3편에서 있던 문제인 정렬에 대한 문제를 해결할겁니다.

어제는 주로 확인했던 창이 우측의 어트리부트 인스펙터 였는데

오늘은 사이즈 인스펙터입니다

아래의 사진과같은곳이죠. 정렬과 크기에 대한 내용을 담고있어서 그런가 아이콘부터가 자모양이죠?

 

위 사진은 Label을 선택한후 오른쪽영역인 익스펙터즈화면에서 6번째아이콘인 사이즈 인스펙터화면입니다

x와 y의 좌표부터 사이즈 그리고 다룰 레이어아웃에 관한 정보를 보여주고 추가 수정,삭제를 할수 있는 공간입니다.

 

어제까지의 프로젝트를 그대로 시뮬레이터만 바꿔서 실행해봅시다!

지원할수 있는 가장 작은 사이즈를 iphone xe라 하면 시뮬레이터를 iphone xe로 변경하고 실행해보세요

 

 

이런...

저희가 원래 원했던 모양이 아닙니다.

오늘은 이 부분을 해결할것이고, 이에대한 해결이 포스트위에서 말씀드린 사이즈 인스펙터창을 확인하면서 진행될겁니다.

우선 가장위에있는 라벨먼저 고쳐보죠.

 

라벨을 잘보시면 원래 의도했던 소수점 내용이 화면에 가려서 안보여요

라벨자체도 가운데에있는게 아니라 치우쳐있군요

 

처음에 라벨을 사이즈및 위치를 선정할때 아이폰11 사이즈를 보면서 했기에 사실 앞쪽(왼쪽) 여백에 대한 문제는 아이폰11사이즈의 화면의 시작점입니다

 

우리는 화면크기가 바뀌어도 일정한 비율을 유지했으면 좋겠는데

이를 지정하는게 바로 앵커입니다

앵커는 다른 UI쪽을 다루는 내용을 해보신분들은 아시겠지만 UI를 다루지않았으면 갑자기 무슨이야기야 라고 하실수 있으니 별로 좋은 단어는 아니겠네요.

 

앞으로 이를 Auto Layout, 이라 할것이고 이를위해 추가해야할 애들을 Constraint라 할겁니다.

물론 이를 코드로 다루다보면 앵커라는 단어를 쓰지만 이 튜토리얼에서는 코드로 오토레이아웃을 다루는일을 하지않을겁니다.

 

이런 단어를 처음 듣는 분은 그냥 아 이런게 있구나 정도로만 생각해두시고 스토리보드창에서 손쉽게 마우스 몇번 클릭으로 추가할 수 있다는것만큼은 기억해주세요

 

라벨을 스토리보드(Main.storyboard를 선택하고 중앙에 위치한 화면)에서 선택하고 아래의 사진에있는 버튼을 눌러주세요

 

중앙영역 하단에 "├ ⎕ ┤" 라고적힌 버튼 부분입니다

이 버튼을 누르면 사지너럼 말풍선이 뜨는데 여기에서 상단(앞으로는 탑이라 부르겠습니다) 좌측(앞으로는 리딩이라...) 우측( ... 트레일링 ...) 하단(... 바텀 ...)의 띄여지는 위치와 높이(Height) 너비(Width)를 고정하거나 가로세로에 대한 비율을 고정(Aspect Ratio) 시키는등의 제약을 걸수 있습니다

Contraint(제약,제한,통제)의 단어뜻처럼말이죠

그러면 아래 사진처럼 라벨에 대한 Constraint를 걸어주세요

 

 

조금 특이하게 탑과 바텀 그리고 높이만 지정해줬어요 그리고 하단의 Add 3 Constraints 버튼을 눌러주시면됩니다

하단의 사진을 보면

Height Equals: 119.5

 

Bottom Space to: Table View

Equals: 16

 

Align Top to: Safe Area

Equals: 16

이  추가가 된것을 확인할 수 있습니다 방금 추가한거에요

 

추가로 이야기하자면 버튼의 Add라는 이름답게 만약 창이 닫아지고 다시 같은 탑이나 바텀같은 내역을 지정해주면 그것또한 추가가되지 변경이 되지않습니다 변경하시려면 아래사진의 사이즈인스펙터에서  변경할 내역을 더블클릭하셔서 수정하시면되요

 

Height Equals: 119.5 를 더블클릭해서 수정모드로 들어가는 화면은 바로 아래화면입니다

First Item 과 Relation 그리고 Constraint 변경으로 이 높이제약조건을 변경할수 있어요

Priority는 이 제약조건이 다른 제약조건에의해 지켜지지못할거같을때, 혹은 변경이되어야할때 누구를 우선순위로 잡을것이냐를 지정해주는건데 이 내용은 다루지 않겠습니다.

 

위의 높이 제약조건 변경화면은 높이이기에 Second Item항목이 없는데

위치(탑,바텀,리딩,트레일링)제약조건일 경우 A가 B로부터 16떨어져야한다 라는같은 지정을위해 Second ITEM 항목이 추가됩니다

 

라벨에대한 제약조건을 더욱줘봅시다.

지금은 탑, 높이 바텀만 줬으니 리딩,트레일링을 줘야할것같지만 저는 화면이 어찌됐던 이 내용이 가운데에 있었으면 좋겠습니다

이럴때 추가하는게 아래 사진에 나와있는 Alignment Constraint 입니다 가운데 정렬을 원하므로 Horizontal in Container를 체크하고 Add를 눌러줍시다

Horizontal과 Vertical은 영단어 그대로 가로이냐 세로이냐입니다 그외 애들은 직접 예를 보여드려야 이해가 되실듯하지만 이 튜토리얼에서는 다루지않기에 넘어갑니다.

그렇게 라벨에 들어갈 제약조건(constraint)를 다 추가해줬지만 스토리보드화면에서는 빨간색으로 테두리와 스토리보드 영역의 좌측상단에는 빨간불(위 사진의 하얀색 실선테두리 상자) 이 들어와있습니다.

 

이를 눌러보면 어떤 제약조건이 문제가 생겼는지 알수 있습니다 한번 들어가보세요

 

내용을 보면 라벨 아래에있는 애들에 대한 제약조건이 없어서 발생하는 문제입니다.

여기에있는 각 항목의 빨간불을 눌러 이 xcode가 제안하는 Constraint를 넣거나 삭제하거나 수정할 수 있지만 이는 권장하지 않습니다.

그럼 테이블뷰와 아래 버튼들에 대한 제약조건을 마져 걸어봅시다.

 

테이블뷰에 넣을 제약조건은 다음과같습니다

잘 보시면 탑에 대한 제약조건을 걸지않았는데 이는 우측영역 사이즈인스펙터에 보면 이 테이블뷰위에 있을애인 라벨이 바텀 제약조건으로 이미 이 테이블뷰의 탑 제약조건이 추가가 되어있는걸(Top Space to: 00:00.0) 확인할 수 있고 이와 겹쳐지지않게 탑 제약조건은 추가하지 않는것입니다. 

 

추가하고나면 90높이로 변경되어 원래 원하던 모양이 아님을 알 수 있습니다. 이는 사실 살짝 변경을 해주기 위해 우선적으로 추가해준거에요. 

 

위 사진에 있는 Height Equals: 90 을 더블클릭해 수정페이지로 들어가줍시다.

그리고 Relation의 Equal 부분을 아래사진처럼 Greater Than or Equal로 변경해줍시다

이 Relation의 내용을 그대로 읽어보면 감이 잡히실건데

다른 제약조건이나 화면크기 변화로 인해 크기가 최소 90이상은 유지해주세요라고 제약을 건겁니다.

이 90은 나중에 추가해줄 랩타임 기록의 한줄정도 표시해줄 사이즈에요.

그래서 화면이 최소로 작아지면서 위(라벨) 아래(버튼)의 위치에 눌려도 최소 90은 보장해줘라! 라고 제약조건을 건겁니다.

 

그리고 이제 버튼들을 손봐줘야하는데

새로운 오브젝트를, Stack View 라는녀석을 추가해줄겁니다.

 

스택은 영어사전(파파고)에 검색보면 

  • 1.(깔끔하게 정돈하여) 쌓다; 쌓이다, 포개지다[VN] to stack boxes책을 포개다
  • 2.(어떤 곳에 물건을 쌓아서) 채우다

라고 뜨는데 이는 각 오브젝트들을 차곡차곡 쌓아 예쁘게 표시해주려고 할때 쓰는 오브젝트입니다.

버튼을 이 스택뷰에 넣어서 깔끔하게 보여주기위해서 사용할거에요

 

그럼 버튼들을 드래그로 전부다 한번에 선택해준뒤 아래의 사진에있는 버튼을 누른후 뜨는 말풍선에서 Stack View를 선택해줍시다

저처럼 스택뷰를 추가하신분은 스토리보드화면에 버튼들이 아래와같이 묶혀있게됩니다.

 

 

이제 이 스택뷰의 설정을 조금 바꿀거게요. 스토리보드에서 스택뷰를 선택하시고(스택뷰안에 있는 버튼이 아닙니다) 우측 인스펙터즈화면을

5번째아이콘인 어트리뷰트 인스펙터로 들어가주세요,

 

여기서, 이 스택뷰에서 주로 다루는 부분이 바로 

Axis 와 Alignment, Distrubution, Spacing 입니다.

 

이 속성들에대한 설명은 애플은 이렇게 적어놨습니다.

There are a number of properties that define how the stack view lays out its content.

  • The axis property determines the stack’s orientation, either vertically or horizontally.

  • The distribution property determines the layout of the arranged views along the stack’s axis.

  • The alignment property determines the layout of the arranged views perpendicular to the stack’s axis.

  • The spacing property determines the minimum spacing between arranged views.

  • The isBaselineRelativeArrangement property determines whether the vertical spacing between views is measured from the baselines.

  • The isLayoutMarginsRelativeArrangement property determines whether the stack view lays out its arranged views relative to its layout margins.

요약하고 저딱 4개만 설명하자면

Asis는 이 스택뷰 가로로 쌓이냐 세로로쌓이냐를 선택하는것이고,

Distribution은 Asis에서 선택한 방향의 레이아웃을

Alignment는 이 축의 수직에대한 레이아웃을

Spcaing 안의 녀석들의 최소간격을 결정한다. 입니다 ㅎ

 

l

이제 이 속성을 위사진에서 아래사진 처럼 변경해주세요.

 

 

그러면 아래와같이 버튼을 묶었던 영여기 작아지게됩니다.

버튼은 스택뷰 좌우로 꽉 차고,  다 같은 높이로 그리고 버튼간 간격은 16 으로 지정한거에요.

 

 

이제 이 스택뷰의 Constraints를 추가해줍시다.

스택뷰를 선택하시고( 스택뷰안에 있는 버튼이 아닙니다)  "├ ⎕ ┤" 버튼( Add new Constraints) 를 클릭후 

아래 사진과 같이 추가해주세요

 

 

그럼 화면이 아래와같이 나올겁니다.

이제 첫 이 튜토리얼의 첫 포스트에서 보여드려던 앱의 모습과 많이 닮아졌네요!

 

이제 그럼 아까 문제가 되었던 아이폰se화면으로 실행해봅시다.

xcode상단의 시뮬레이터를 iPhone SE로 변경해주고 실행해주세요!

 

 

이런...

타임을 표시해줄 라벨이 양옆이 조금씩 벗어났습니다.

이건 라벨의 크기는 그대로 유지되고 라벨의 가운데는 화면의 가운데로 가져갔으나 양옆에 대한 제약조건이 없기에 발생한문제인데요.

이를 리딩, 트레일링을 넣어줬으면 밖으로 빠져나가지는 않았을겁니다( 대신 라벨의 끝부분이 ... 으로 짤렸을겁니다)

이에 대한 문제는 글자 크기를 줄여주거나 리딩 트레일링을 주면서 자동으로 글자가 작아지게끔 설정을 해주면되는데

우리는 이렇게 주지않을것이고 사실 저 라벨은 임시적으로 달아둔거라 다른모양으로 변경할것입니다.

튜토리얼 1편의 앱에서처럼 변경할거 거든요!

이에대한것은 다음편에서 다루겠습니다

 

그럼 다음편에서 봐요~

반응형

스톱 워치 만들기 (1) : https://wiwi-pe.tistory.com/34

스톱워치 만들기 (2) : https://wiwi-pe.tistory.com/35

 

저번 2편까지 무사히 끝내셧다면 앱이 시뮬레이터로 무사히 실행이 되었으나

앱에 아무것도 없었을겁니다.

 

이제 앱에 채워넣을 차례입니다.

 

1편에서 본 만들려고하는 앱의 화면을 다시한번 보자면

 

 

위 에서 부터 차례대로

시간을 표시하는 부분 

랩타임을 표시하는 부분

그리고

 

시작 버튼

랩타임 체크 버튼

정지 버튼

초기화 버튼

 

이런식으로

 

크게 

시간표시, 랩타임표시, 버튼부분 세부분으로 나눠져 있습니다.

 

우리는 이 화면을 구성하기위해 애플에서 제공해주는 오브젝트들로 붙여넣을꺼에요

 

설명은 뒤에서 하고 우선 넣을것들 나열하자면

 

UILabel

UITableView

UIButton

 

이렇게 세종류와 

추가로

UITableViewCell 이라는 녀석이 이 앱화면을 구성하게 됩니다.

 

 

 

 

 

 

화면 구성을 시작하기전에 에디터에 보여지는 방식을 저랑 맞추겠습니다.

 

에디터메뉴에 아래 사진처럼 체크해주세요!

 

 

다시 앱화면 구성에 대해서 이야기하겠습니다.

 

우선 UILabel에 대해 이야기하자면

U는 내버려두고 Label을 사전(파파고)에 검색하면 

아래와 같이 나옵니다

 

label[ˈleɪbl]명사

  • 1.(종이 등에 물건에 대한 정보를 적어 붙여 놓은) 표
  • 2.(사람물건의 성격 등을 묘사하는) 딱지
  • 3.음반사, 레이블

다들 아시다 싶이 그냥 라벨이에요

라벨을 라벨이라 부르지못하고 레이블이라 불러야한다지만 저는 앞으로도 라벨로 부르겠습니다........

 

이 UILabel은 애플이 이렇게 설명하고있습니다.

 

A label can contain an arbitrary amount of text, but UILabel may shrink, wrap, or truncate the text, depending on the size of the bounding rectangle and properties you set. You can control the font, text color, alignment, highlighting, and shadowing of the text in the label.

 

텍스트를 포함하고, 뭐 각종 속성들을 넣어 제어할 수 있다고하네요

 

라벨이라는 이름답게 글씨를 표시해주는애 입니다. Text를 표시해주는애인데 

이 앱에서는 다루지않을 다른 텍스트를 표시해주는 녀석들도 있습니다.

 

TableView는 다음에 설명을 할것이고 버튼을 이야기하자면

누구나 다 예상하시듯이 버튼입니다

 

애플은 이 버튼 오브젝트를 아래와같이 설명해주고 있어요

 

You can set the title, image, and other appearance properties of a button. In addition, you can specify a different appearance for each button state.

 

제목, 이미지 기타 속성을 넣고 각 상태따라 다른게 설정을 해줄수있다!

이 상태가 매우 중요합니다.

 

각 오브젝트들에 대해 자세히 다루지는 않을테니 더 궁굼하신분은 애플디펠로퍼의 도큐먼트 페이지들을 봐주세요

 

그럼 

 

우선은 라벨을 넣어서 실행해보죠

 

프로젝트화면의 좌측의 프로젝트 네비게이션에서 Main.storyboard를 누르시면 가운데 화면이 마치 아이폰 시뮬레이터같은 모양으로 변경됩니다.

 

이 하얀 녀석을 마우스로 클릭하면 네비게이션 옆에 있는, Structure Area의 View가 선택되었다고 하일라이트가 될겁니다

앞으로 이 뷰 안에 표시할애들을 넣어줄거에요.

 

뷰안에는 이미 Safe Area가 속해있는데

이는 실제적으로 있는 것이 아니라 실제 화면만 보여질곳, 상단 스테이터스바와 하단 홈바를 제외하고 있는 가운데에 남겨진 영역에 대해 알려주기위한 일종의 가이드라인입니다

 

앞으로 이 가이드 라인에 대한 도움을 많이 받을거에요

 

위 사진의 보라색 실선부분, + 버튼 또는 키보드로 command + shift + L 을 누르면 아래와같은 창이 뜹니다

 

위에 사진처럼 우측에 설명칸이 나와 있을 수도 있고 없을수 도 있습니다.

설명창을 펼치거나 혹은 닫고싶으시면 팝업창 상단의 검색바 옆의 두번째 창모양 버튼을 누르시면되요

 

이제 창에서 보이는 Label을 아까 선택했던 뷰로 드래그 하고 드롭 해주세요

 

그럼 아래와 같이 드롭한 장소에 라벨이 하나 생겼을겁니다.

 

그리고 이 라벨을 더블클릭하면 이 텍스트를 수정할 수 있게됩니다!

아래 사진처럼요

 

 

그리고 옆의 

인스펙터영역이 아래와 같이 5번째가 선택되어 딱봐도 이 라벨에 대한 설정을 변경 할 수 있는 창이구나! 라고 알만하게 여러 속성을이 있습니다

 

이 어트리뷰트 인스펙터창에서 텍스트를 수정하거나, 색상, 정렬 크기 등등 많은걸 수정 할 수 있어요

 

 

스토리보드를 통해 작업을하면 기본적으로 이런식으로 뷰에 필요한 오브젝트를 넣고 설정을해주는 식으로 화면을 구성하게 됩니다.

 

 

 

 

이제 아까 라벨을 추가한것처럼

 

라이브러리버튼(+버튼)을 눌러서 저희가 사용하려하는

 

테이블뷰, 버튼들을 배치해줍시다

 

추가로 넣으려는 오브젝트들은 아래와같습니다 

 

항목을 잘 선택하셔서 드래그 앤 드롭해주세요

아래와같이요!

그리고 이제 

각각의 오브젝트들을 선택하시면 각 사각형이 크기가 수정가능하게 변하는데 이를 잘 조절하여 최대한 만드려는 앱과 비슷하게 만들어줍시다.

 

이제 글자 크기와 색상을 맞춰줄꺼에요.

우선 라벨의 속성은 아래와같이 설정해줄겁니다

라벨을 선택하고

우측의 인스펙터즈 창을 어트리뷰트 인스펙터로 변경되는것을 확인한후

font 는 system 100.0

Alignment 는 가운데로 설정합니다

 

그후 버튼의 색상과 글자크기를 변경할겁니다

우선 Stop버튼을 눌러서 아래와같이 변경해줍시다

그러면 아래와같이 스톱버튼이 변했을거에요.

 

 

나머지 버튼들도 만드려고하는 앱의 화면처럼 변경해줍시다.

 

Start Button , Check Button

font를 30포인트로 올리고 변경없음

 

Reset Button

font를 30포인트로 올리고 Text Color 를 Label Color로 설정

 

아래의 사진과 같이되면 됩니다

 

뭔가 조금 정렬이 안맞고 크기도 잘안맞는거 같고 그렇죠?

그 부분은 다음 포스트에서 다루겠습니다!

 

오늘 우선한것을 command + r 키 또는 실행버튼으로 시뮬레이터로 돌려보세요

아래와같이 나온다면 이번 튜토리얼도 성공입니다

 

 

 

그럼 다음 포스트에서 봐요~

반응형

 

이제 막 iOS 개발에 손을 대고자 하는 분들을 위해 아래의 영상에서 나오는 스톱워치를 만드는 튜토리얼을 시작해보려고합니다.

일단 개발을 위해 필요한 준비물은

 

xcode11이 설치되는 macOS 10.14.4 버전 이상의 맥PC,

그리고 애플 계정입니다.

 

튜토리얼에서 만들앱은 xcode에서 제공해주는 시뮬레이터로만 돌릴것이고 개발자계정(유료)은 없어도 학습이 가능합니다.

 

단, 학습용이라고 할지라도 애플계정은 필요해요

 

맥을 구입하셨고, 처음 사용자세팅을 완료하셨다면 분명 다들 애플 계정이 있을꺼라 생각됩니다.

 

 

macOS 10.14.4 이상으로 제한한 이유는

swift5의 컴파일러를 사용하기 위해서입니다.

실제로는 그 이하 버전이라도 개발은 가능해요

 

 

그리고 위에서 말씀드린 실행영상입니다.

 

이 영상은 시뮬레이터(iphone11, ios13)의 화면이에요.

 

기본, 라이트 모드에서의 동작화면 

기본 모드 화면

 

 

다크 모드 화면

다크 모드

 

우선 위에 영상에서 나오는 앱의 기능을 정의해야합니다.

 

1. 분,초, 1/10초의 시간 표시가 되어야합니다. 이는 물론 스톱워치 기능을 시작하면 실시간으로 시간이 표시되어야하죠.

2.  랩타임을 기록하고싶습니다. 스톱워치면 당연히 있어야겠죠?

3. 언제든 스톱워치를 처음상태로 돌아가는 리셋기능도 만들어주세요!

4. 요즘 ios13에는 다크모드라고 검은색버전도 있던데 지원가능하게해주세요!

 

그렇게

요청사항은 크게 4가지가 되겠습니다.

 

그럼 다음 포스트는 프로젝트를 만드는것으로 만나뵙겠습니다 ㅎ

반응형

모달형식을꽤나 자주 쓰는 앱인데 ( present() )

모달을 띄우면 기존엔 풀스크린으로 깔끔히 보이던게 ios13에서는 상단에 이상한 모양의 카드? 형식처럼 모달이 표시된다.

 

멘붕상태에 빠지고 구글신님께 문의를해보니

 

"""

iOS 13.0부터 iOS에서는 UIModalPresentationAutomatic이 기본값이고, 이전 버전에서는 UIModalPresentationFullScreen입니다.

기본적으로 UIViewController는 UIModalPresentationAutomatic을 UIModalPresentationPageSheet로 해석하지만 다른 시스템 제공보기 컨트롤러는 UIModalPresentationAutomatic을 다른 구체적인 프리젠 테이션 스타일로 해석 할 수 있습니다.

"""

라고한다.

 

그리하여.

.modalPresentationStyle 을 풀스크린으로 변경해주면 

ios13에서도 정상적으로 뜬다.

 

물론 이것만으로 모든게 정상적으로 돌아가는게 아니였다.......

 

이유는 모르겠지만 컨테이너뷰로 만든애의 옆구리가 빈다....................

 

너네 왜그러니 ㅠㅠ

 

참고로 옆구리가 비어있는 문제는 ios13 xr 시뮬레이터 이상에서만 나온다.

기존 타겟으로 삼은 기기 6s에선 ios13으로도 문제없이 프린트가 된다.

 

도대체 뭐가 문제였을까

ios12로 돌리던 xr에선 문제없이 보이건만 슬플따름

 

이거에대한 문제가 해결되면 나중에 다시 관련내용으로 글을 작성할 예정이다.

 

 

 

==========================================================================

추가

 

옆구리가 비는 문제는 몇몇의 기기에서만 발생하는문제였다.

임시적으로

viewWillLayoutSubviews 에서 크기와 위치를 재설정해줘서 땜빵해놨다.

이 이후에 문제가 뭔지 발견하면 수정할 예정.

반응형

현재 연결된 WiFi의 SSID값을 받아와서 내가 연결하려한SSID와 같은지 비교해서

앱내에서 연결이 됐는지 확인하는 예제를 만들고 있었으나,

func currentSSIDs() -> [String] {
    guard let interfaces = CNCopySupportedInterfaces() as? [String] else {
        return []
    }
    return interfaces.compactMap { interfaceName in
        guard let info = CNCopyCurrentNetworkInfo(interfaceName as CFString) as? [String:AnyObject] else {
        	print("Point 0")
            return nil
        }
        guard let ssid = info[kCNNetworkInfoKeySSID as String] as? String else {
        	print("Point 1")
            return nil
        }
        return ssid
    }
}

ps. 해당소스는 https://codeday.me/ko/qa/20190625/886103.html 를 보고 살짝 바꾼 코드이다.

(iOS11 이상부터?  단순 Nil값 제거는 flatMap 대신 compactMap 을 쓰는걸 권장하고있다)

 

currentSSIDs 의 값이 항상 nil이 나오고

console에 Point 0가 찍힌다.

 

처음에는 뭔가 키라던가 변경되어 값을 잘못 참조하고있는줄 알았다.

그렇게 키값 위주로 검색해보던중 우연찮게

잘못된곳은 그곳이 아니라는걸 알게되었고

문제는 아래 스택오버플로우의 글과 같았다.

 

https://stackoverflow.com/questions/50767946/systemconfiguration-captivenetwork-doesnt-work-on-ios-12 

 

테스트하고 있던 폰은 iOS12 로 WiFi 정보를 받아오려면

Project File -> Capabilities 의 Access WiFi Information 을 on으로 변경해줘야한다.

 

변경해주었더니 잘 받아옴....

반응형

+ Recent posts