APNs 기능 때문에 p12 개발 인증서가 필요했는데 p12로 개발 인증서 내보내기가 안되서 몇 시간을 삽질하다가 해결했습니다.

옛날 인터페이스의 자료가 많아서 찾는데 고생했기에

공부용으로 남기기 위해 포스팅을 작성합니다.

 

본 글은 macOS Monterey 버전 12.0.1 을 기준으로 작성합니다.

 

1. 키체인 접근

1. '키체인 접근'을 열어줍니다.

 

2. 메뉴에서 '인증 기관에서 인증서 요청'을 눌러줍니다.

 

3. 인증서 정보에 '사용자 이메일 주소'(애플 개발자 계정)와 요청 항목에 '디스크에 저장됨' 체크를 해줍니다.

 

4. 그럼 바탕화면에 'CertificateSigningRequest.certSigningRequest' 파일이 생기는데요.

 

2. 애플 개발자 사이트에 업로드

1. 애플 개발자 사이트에 업로드 할것이므로 https://developer.apple.com/ 여기로 들어가줍니다.

Account 로 들어가서 애플 개발자 계정으로 로그인 해줍니다. (애플 개발자 계정 만드는 방법은 검색해보시면 많이 나와요.)

 

2. 가운데 혹은 왼쪽의 항목으로 이동해줍니다.

 

3. Identifiers 로 이동해서 자신의 프로젝트를 클릭해줍니다.

4. Push Notifications 체크하고 Edit 눌러줍니다.

 

5. Development(개발용)과 Production(배포용) 두가지가 있는데 저는 개발용으로 할거라 Development 에 'Create Certificate' 눌러줄게요. 배포용으로 하실분은 Production 눌러주세요.

 

6. Choose File 눌러줄게요.

 

7. 여기에서 아까 바탕화면에 다운받은 인증 파일을 열어줍니다. 그리고 Continue 눌러줄게요.

 

8. 그리고 Download 받아줘요.

 

3. p12 로 개발 인증서 내보내기

1. aps_development.cer 이 파일이 생기는데요. 이 파일을 실행해줍니다.

 

2. 그러면 키체인 접근이 켜질거에요.

 

3. 여기서가 중요한데. 기본 키체인의 '로그인' 항목에 '내 인증서' 메뉴에서 자기 프로젝트에 마우스 우클릭하면 '내보내기'가 보입니다. 클릭해줄게요.

 

4. 그럼 파일 포맷에 '개인 정보 교환(.p12)' 선택가능하고 저장해서 쓰시면 되요. 만약 메뉴를 '모든 항목'으로 선택하고 내보내기 하면 p12가 선택이 안됩니다. 꼭 '로그인' 항목에 '내 인증서' 메뉴에서 눌러주세요.

 

--참고 내용

'iOS > 문제 해결' 카테고리의 다른 글

TableViewCell 의 textLabel 대체  (0) 2021.10.22
iOS 기존의 프로젝터에 코어데이터 추가하기  (0) 2021.08.13

개요

오토레이아웃 → 자동으로 그리는것

 

화면을 그릴려면 해당 뷰의 위치를 알아야 한다.

위치를 고정한다. → 앵커를 건다.

사이즈 설정

앵커를 걸고 사이즈를 설정하면 iOS에서 자동으로 계산해서 뷰를 그려준다.

 

option/alt 키를 누르면 사이즈가 나온다.

 

값 수정하는 방법

constraint 자체를 눌러서 값 수정이 가능하다.

객체를 선택한 후 Size inspector 탭에서 constraint 를 선택해서 값 수정도 가능하다.

 

constraint 제거하는 방법

문서 개요창에서 값 선택해서 제거 가능

Resolve Auto Layout Issues 에서 Clear Constraints 를 선택해서 한번에 제거도 가능

 

constraints 자동 추가

안잡혀 있는 constraint 를 자동으로 추가해준다.

 

 

 

수직/수평 정렬

align 을 설정하면 뷰의 객체의 크기를 스크린을 반으로 나누어서 위치를 계산한다.

 

xcode는 스크린의 크기를 알고 스크린을 반으로 나눈 값에서 뷰의 크기를 뺀 나머지 값을 자동으로 설정해준다. 따라서, 정렬을 잡아주면 뷰의 크기나 위치 중 하나만 잡아주어도 된다.

 

 

 

 

 

 

 

오토레이아웃 기본 정리

 

 

💡
X 축: 두 개의 위치(좌, 우) 값 중 하나를 잡아주고 뷰의 크기(Width) 를 잡아주면 Xcode 는 디바이스의 스크린의 크기를 알기 때문에 스크린크기 - 위치(좌) - 뷰의 크기(Width) = 위치(우) 를 자동으로 잡아준다.

 

 

 

 

 

 

 

 

 

'iOS > Swift' 카테고리의 다른 글

iOS의 비동기 관리  (0) 2021.09.05
DispatchQueue.main.sync 사용 시 주의사항  (0) 2021.09.05
DispatchQueue의 의존성  (0) 2021.09.05
DispatchQueue 특징  (0) 2021.09.05
비동기에서의 NSLock() 간단 비교  (0) 2021.09.05

iOS 15 가 나오고 Xcode 13이 나오면서 textLabel에 deprecated 가 떴다.

애플 개발자 문서

 

Apple Developer Documentation

 

developer.apple.com

그래서 테이블 셀 내용 호출하는 방식이 달라졌다.

 

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "MessageCell", for: indexPath)
        
        // 달라진 방식(iOS 14.0 이상)
        if #available(iOS 14.0, *) {
            var content = cell.defaultContentConfiguration()
            content.text = self.comments[indexPath.row].message
            cell.contentConfiguration = content
        } else {
        // 기존과 동일(iOS 14.0 까지만 지원)
            cell.textLabel?.text = self.comments[indexPath.row].message
        }
        
        return cell
    }

 

- 문제 링크

https://programmers.co.kr/learn/courses/30/lessons/42587

 

코딩테스트 연습 - 프린터

일반적인 프린터는 인쇄 요청이 들어온 순서대로 인쇄합니다. 그렇기 때문에 중요한 문서가 나중에 인쇄될 수 있습니다. 이런 문제를 보완하기 위해 중요도가 높은 문서를 먼저 인쇄하는 프린

programmers.co.kr

난이도: Level 2

 

- 제출 답안

import Foundation

func solution(_ priorities:[Int], _ location:Int) -> Int {
    var copyPriorities = priorities
    var wait = Array(0 ... priorities.count-1)
    
    let waitLocation = wait[location]
    
    var indexPriorities = 0
    while indexPriorities != copyPriorities.count-1 {
        if copyPriorities[indexPriorities+1 ... copyPriorities.count-1].contains(where: { $0 > copyPriorities[indexPriorities] }) {
            copyPriorities.append(copyPriorities.remove(at: indexPriorities))
            wait.append(wait.remove(at: indexPriorities))
        } else {
            indexPriorities += 1
        }
    }
    
    let paperSeq = wait.firstIndex { value in
        value == waitLocation
    }
    
    return (paperSeq!+1)
}

 

- 풀이

priorities 인덱스를 체크해줄 값을 하나 초기화 해준다.(indexPriorities = 0)

그리고 대기문서 배열을 구하기 위해 priorities 크기 만큼의 배열을 하나 초기화 해준다.

var wait = Array(0 ... priorities.count-1)

 

priorities내부에 index 뒤부터 끝 인덱스까지의 값 중 index 값 보다 큰 값이 있다면,

priorities 의 해당 인덱스 값을 뒤로 옮겨주고 마찬가지로 대기문서(wait)의 해당 인덱스 값도 뒤로 옮겨준다.

 

큰 값이 없다면, 더 비교할 필요가 없기 때문에 index를 하나 증가해준다. 그렇게 마지막 요소까지 검사한다.

 

대기문서에서 값 정렬 전의 location 위치의 값을 구해주고 값 정렬이 끝난 뒤, 그 값의 위치를 구해준다.

 

처음에 Dictionary를 이용해서 풀어보려 하다가 정렬 문제로 애먹어서 배열을 두개 이용하는 방법으로 접근하니 좀 더 쉽게 풀렸다.

- 문제 링크

https://programmers.co.kr/learn/courses/30/lessons/64061

 

코딩테스트 연습 - 크레인 인형뽑기 게임

[[0,0,0,0,0],[0,0,1,0,3],[0,2,5,0,1],[4,2,4,4,2],[3,5,1,3,1]] [1,5,3,5,1,2,1,4] 4

programmers.co.kr

난이도: Level 1

 

- 제출 답안

import Foundation

func solution(_ board:[[Int]], _ moves:[Int]) -> Int {
    var newBoard = board
    
    var basket = [Int]()
    var result = 0
    
    for move in moves {
        for (key, line) in newBoard.enumerated() {
            if line[move - 1] != 0 {
                basket.append(line[move - 1])
                newBoard[key][move - 1] = 0
                break
            }
        }
        
        if basket.count > 1, basket[basket.endIndex - 1] == basket[basket.endIndex - 2] {
            basket.removeLast()
            basket.removeLast()
            result += 2
        }
    }
    
    return result
}

 

- 풀이

먼저 보드에 있는 숫자를 바구니에 옮긴다. 보드에 있는 숫자를 바구니에 넣고 보드에 숫자가 있던 자리는 0으로 대체한다. 이때, 0이 아닌 숫자만 옮긴다.

그리고 바구니에 숫자가 1개만 있다면 인덱스 오류가 나기 때문에 2개 이상일때, 마지막 두개의 숫자만 비교하여 같다면 마지막 두개의 숫자를 지우고 지운 갯수인 result에 2씩 더해준다.

이 과정을 moves에 있는 요소만큼 반복한다.

터미널

코코아팟 라이브러리 생성

라이브러리를 만들 경로로 이동하여 라이브러리를 만들어준다.

 

pod lib create 이름

 

그 뒤에 나오는 5가지 질문에 대답해준다.

1. 어떤 플랫폼을 사용하시겠습니까?

iOS

2. 어떤 언어를 사용하시겠습니까?

Swift

3. 라이브러리에 데모 애플리케이션을 포함하시겠습니까?

Yes

데모 앱으로 테스트를 해볼 수 있다.

4. 어떤 테스팅 프레임워크를 사용할 것인가?

None

5. 보기 기반 테스트를 하시겠습니까?

No

 

4번과 5번을 Quick, Yes 로 입력하면 오류가 걸릴 수도 있다.

 

이렇게 하면 pod이 설치되고 Xcode 프로젝트가 자동으로 실행된다.

 


Xcode

라이브러리 수정

Pods - Development Pods - 라이브러리 이름 - ReplaceMe.swift

파일 이름을 라이브러리명으로 수정하고 파일 내용을 입력한다.

외부에서 import 해서 사용하기 위해서 반드시 open 이나 public 으로 작성해야 한다.

 

라이브러리 테스트

Example 에 있는 ViewController를 수정하여 테스트를 해본다.

아까 라이브러리 생성할때 3번에 Yes 체크한게 이부분이다!

실행하면 출력이 잘 되는걸 확인할 수 있다.

 

Podspec 수정

 

git 원격 저장소 생성

레파지토리 이름은 라이브러리에 맞추어 주고 public으로 생성해줍니다.

 

깃허브 레파지토리 확인

깃허브로 들어가서 확인해보면 아래와 같이 올라와 있습니다.

(저는 출시하고 캡쳐한거라 pod, license 가 변경되어 있는데 처음 올리면 비어져 있어요.)

 

코코아팟에 배포하기

podspec 확인

터미널

먼저 .podspec 파일에 이상이 없는지 체크해야한다.

터미널에서 라이브러리 프로젝트 경로로 이동한다. 그리고 명령어를 입력한다.

pod spec lint

 

만약 '원격 저장소'에 0.1.0 버전 태그가 없다는 에러가 뜬다면 태그를 만들어줘야 한다.

 

0.1.0 태그 버전 업데이트

Xcode

Xcode에서 Commit 및 Push to remote를 같이 해준다.

터미널

라이브러리 프로젝트 경로의 터미널에서 명령어를 입력해준다.

git tag 0.1.0
git push origin 0.1.0

0.1.0 버전 태그를 붙이고 레파지토리에 push 해주는 것이다.

 

그리고 다시 podspec 파일 체크를 해준다.

pod spec lint

여기에서 에러나 경고가 없다면 passed validation 이 뜬다.

(경고를 그냥 무시하고 싶으면 pod spec lint --allow-warnings 입력)

 

코코아팟에 등록하기

pod에 등록해 주기 위해 터미널에 명령어를 입력한다.

pod trunk register 이메일주소 이름

 

이메일로 이동해서 링크를 확인한다.

코코아팟 사이트로 이동되고 셋업이 완료되었다고 뜬다.

 

코코아팟에 출시하기

터미널에서 라이브러리를 코코아팟에 푸쉬해준다.

pod trunk push 라이브러리이름.podspec

여기에서 자신의 맥이 M1 이라면 에러가 뜹니다. M1 터미널 호환문제로 인한 에러입니다.

그러면 아래와 같이 명령어를 수정해주세요.

arch -x86_64 pod trunk push 라이브러리이름.podspec

arch -x86_64 명령어는 터미널을 인텔맥처럼 돌아가게 만들어주는 명령어입니다.

(코코아팟 설치할때와 마찬가지 에러)

 

그리고 경고를 무시하고 싶으면 명령어를 다시 수정합니다.

arch -x86_64 pod trunk push 라이브러리이름.podspec --allow-warnings

 

성공하면 축하한다는 메시지를 받게되요.

 

코코아팟 출시 확인하기

위에 보이는 링크(https://cocoapods.org/pods/ReusingFramework)를 인터넷주소창에 입력하면 자신의 깃허브 레파지토리로 이동됩니다.

pod: v0.1.0, license:MIT 로 변경되어 있으면 성공입니다.

 

정말 간혹 변경이 안되어 있을 수 있는데 코코아팟 사이트(https://cocoapods.org/)로 이동시 Internel Server Error 가 뜨면서 로드가 안될 수 있는데 코코아팟 내부 서버 문제입니다.(제 경우가 그랬어요...)

 

코코아팟 설치로 내가 등록한 라이브러리가 잘 불러와지는지 확인해보면 됩니다.

'iOS > 기술' 카테고리의 다른 글

MVVM, Reactive, RxSwift  (0) 2021.08.17
REST API 란?  (0) 2021.08.17
React Native 란?  (0) 2021.08.17

- 문제 링크

https://programmers.co.kr/learn/courses/30/lessons/42862

 

코딩테스트 연습 - 체육복

점심시간에 도둑이 들어, 일부 학생이 체육복을 도난당했습니다. 다행히 여벌 체육복이 있는 학생이 이들에게 체육복을 빌려주려 합니다. 학생들의 번호는 체격 순으로 매겨져 있어, 바로 앞번

programmers.co.kr

난이도: Level 1

 

- 제출 답안

import Foundation

func solution(_ n:Int, _ lost:[Int], _ reserve:[Int]) -> Int {
    var losted = lost.sorted(by: <).filter{!reserve.contains($0)}
    var reserved = reserve.sorted(by: <).filter{!lost.contains($0)}

    for value in losted {
        if reserved.contains(value - 1) {
            losted.remove(at: losted.firstIndex(of: value)!)
            reserved.remove(at: reserved.firstIndex(of: value - 1)!)
        } else if reserved.contains(value + 1) {
            losted.remove(at: losted.firstIndex(of: value)!)
            reserved.remove(at: reserved.firstIndex(of: value + 1)!)
        }
    }
    
    return (n - losted.count)
}

 

- 풀이

  • 여벌 체육복을 가져온 학생이 체육복을 도난당했을 수 있습니다. 이때 이 학생은 체육복을 하나만 도난당했다고 가정하며, 남은 체육복이 하나이기에 다른 학생에게는 체육복을 빌려줄 수 없습니다.

먼저 이 경우의 수를 해결해야 한다.

n=5, lost=[1,2,3], reserve=[2,3,4] 답:4

이런 테스트 케이스가 있다면 '내가 잃어버렸을 경우 빌려줄 수 없다'가 성립되지 않으면 답이 5가 되버린다. 그래서 lost와 reserve에 중복되는 값부터 제거해준다.

그리고 배열에 값이 순서대로 들어있지 않았을때 앞번호 먼저 비교를 해주기 위해 정렬을 해준다.

그 뒤에는 앞번호가 먼저 비교하고 그 다음 뒷번호를 비교하는 방식으로 lost와 reserve에 있는 값을 차례로 제거해 주면 된다.

참고 강의 링크

 

GCD와 Operation

 

GCD와 Operation의 차이

코드 예시

 

 

Synchronous(동기) VS Asynchronous(비동기)

syns: 다른 스레드에 보낸 작업을 '기다리고' 자신의 다음 작업을 처리한다.

async: 다른 스레드에 보낸 작업을 '기다리지 않고' 자신의 다음 작업을 처리한다.

 

동기 개념

 

비동기 개념

 

 

Serial(직렬) VS Concurrent(동시)

serial: 다른 '하나의 스레드'에 작업을 보낸다.

concurrent: 다른 '여러 스레드'에 작업을 보낸다.

 

Serial 큐 개념

 

Concurrent 큐 개념

 

'iOS > Swift' 카테고리의 다른 글

오토레이아웃 - 개념  (0) 2021.10.25
DispatchQueue.main.sync 사용 시 주의사항  (0) 2021.09.05
DispatchQueue의 의존성  (0) 2021.09.05
DispatchQueue 특징  (0) 2021.09.05
비동기에서의 NSLock() 간단 비교  (0) 2021.09.05

사이트 링크

 

[iOS - swift] DispatchQueue.main.sync 사용 시 주의사항 (Deadlock)

기초: Sync vs Async vs Serial vs Concurrent 개념 Deadlock (교착 상태) 두 개 이상의 process 및 thread가 서로 상대방의 작업이 끝나기만을 기다리고 있어서 task들을 처리하지 못하는 상태 ex) deadlock Seri..

ios-development.tistory.com

 

'iOS > Swift' 카테고리의 다른 글

오토레이아웃 - 개념  (0) 2021.10.25
iOS의 비동기 관리  (0) 2021.09.05
DispatchQueue의 의존성  (0) 2021.09.05
DispatchQueue 특징  (0) 2021.09.05
비동기에서의 NSLock() 간단 비교  (0) 2021.09.05

참고 사이트 링크

참고 사이트 링크

 

Global의 concurrent 특성

global은 concurrent 특성으로 여러 스레드에서 병행 처리 하기때문에 의존성 있게 데이터 관리를 할 수 없다.

var money = 10000

DispatchQueue.global().async {
    buy()
}

DispatchQueue.global().async {
    buy()
}

func buy() {
    money = money - 1000
    print(money)
}

9000

9000

 

 

main의 serial 특성

main은 serial 특성으로 다른 하나의 스레드에 작업을 넘겨주기 때문에 의존성 있게 데이터를 처리하게 된다.

var money = 10000

DispatchQueue.main.async {
    buy()
}

DispatchQueue.main.async {
    buy()
}

func buy() {
    money = money - 1000
    print(money)
}

9000

8000

'iOS > Swift' 카테고리의 다른 글

iOS의 비동기 관리  (0) 2021.09.05
DispatchQueue.main.sync 사용 시 주의사항  (0) 2021.09.05
DispatchQueue 특징  (0) 2021.09.05
비동기에서의 NSLock() 간단 비교  (0) 2021.09.05
12.2.2. 영화관 정보 API  (0) 2021.09.02

참고 사이트 링크

 

스레드를 사용할 때에 비해서, DispatchQueue가 얻을 수 있는 이점

  1. 스레드를 만들고 관리하는 것을 시스템이 하기 때문에 훨씬 간결하다. 시스템은 현재 시스템 상태와 자원에 따라 유동적으로 스레드 수를 조절할 수 있고, 종종 더 빠르게 작업을 시작할 수도 있다.
  2. Serial의 경우는, 작업의 수행순서가 보장되기 때문에 lock을 사용하지 않고도 동기화가 가능해진다. 덕분에 불필요한 커널 모드 진입을 최소화 할 수 있다.(물론 여러개의 SerialQueue가 같은 자원에 접근하게 하면 문제가 된다.)
  3. 스레드를 만들때 커널 영역과 유저 영역 메모리를 모두 확보해야하는 비용이 드는데, DispatchQueue는 이러한 비용이 들지 않는다.
  4. DispatchQueue를 통해 생성된 스레드는 클록되지 않고 계속해서 연산을 수행한다.

그 외에도 DispatchQueue가 가지는 특징

  1. DispatchQueue의 순차성은 한 Queue 단위에서만 적용된다.
  2. 아무리 Queue를 많이 만들어도, 동시에 수행되는 작업의 수는 시스템에 의해 결정된다.
  3. 시스템은 새로이 수행할 작업을 결정할 때, Queue의 우선순위를 고려한다.
  4. Queue에 작업이 들어갈 때, 이미 실행할 준비가 완료된 상태여야 한다.

'iOS > Swift' 카테고리의 다른 글

DispatchQueue.main.sync 사용 시 주의사항  (0) 2021.09.05
DispatchQueue의 의존성  (0) 2021.09.05
비동기에서의 NSLock() 간단 비교  (0) 2021.09.05
12.2.2. 영화관 정보 API  (0) 2021.09.02
12.3. 영화관 목록 화면 구현하기  (0) 2021.09.02

비동기로 동일 함수 실행

비동기로 같은 함수를 실행하게 되면 동시에 실행해서 같은 결과 값을 내게 됩니다.

import Foundation

var money = 10000

DispatchQueue.global().async {
    buy()
}

DispatchQueue.global().async {
    buy()
}

func buy() {
    money = money - 1000
    print(money)
}

9000

9000

 

 

sleep으로 동시 호출 방지

하나의 스레드가 실행될때 잠시 멈추게 하여 실행 간격에 차이를 둘 수도 있습니다.

var money = 10000

DispatchQueue.global().async {
    buy()
}

DispatchQueue.global().async {
    sleep(1)
    buy()
}

func buy() {
    money = money - 1000
    print(money)
}

9000

8000

 

 

lock으로 동시 호출 방지

만약 실행 간격에 차이를 두는것이 아니라 '하나의 스레드가 함수를 사용 중일때, 다른 스레드에서 접근을 못하게 하려면?'

var money = 10000
let lock = NSLock()

DispatchQueue.global().async {
    buy()
}

DispatchQueue.global().async {
    buy()
}

func buy() {
    lock.lock(); defer {lock.unlock()}
    money = money - 1000
    print(money)
}

9000

8000

 

이렇듯 NSLock()으로 lock을 걸면 시간 간격 차이를 두는 것과 같은 출력값이 나오게 됩니다.

순서는 이렇습니다.

Thread 1 buy() 실행, lock() -> 다른 스레드에서 접근 못함 -> Thread 2 buy() 대기 -> Thread 1 buy() 실행 후 unlock() -> 다른 스레드에서 접근 가능 -> Thread 2 buy() 실행, lock() -> 다른 스레드에서 접근 못함 -> Thread 2 buy() 실행 후 unlock()

 

 

다른 스레드 사용 방지

unlock으로 잠금해제를 하지 않게 된다면? 다른 스레드에서 접근을 하지 못한채로 끝나게 되겠죠.

var money = 10000
let lock = NSLock()

DispatchQueue.global().async {
    buy()
}

DispatchQueue.global().async {
    buy()
}

func buy() {
    lock.lock()
    money = money - 1000
    print(money)
}

9000

'iOS > Swift' 카테고리의 다른 글

DispatchQueue의 의존성  (0) 2021.09.05
DispatchQueue 특징  (0) 2021.09.05
12.2.2. 영화관 정보 API  (0) 2021.09.02
12.3. 영화관 목록 화면 구현하기  (0) 2021.09.02
이미지 비동기 처리하기  (0) 2021.08.14

Request URI

http://swiftapi.rubypaper.co.kr:2029/theater/list

 


요청

요청할 인자값 목록

항목 데이터 타입 샘플 값 설명
s_page 정수 1 페이지 번호
s_list 정수 100 페이지 크기
type 문자열 json 데이터 형식

 

URI 샘플

http://swiftapi.rubypaper.co.kr:2029/theater/list?s_page=1&s_list=100&type=json

 


응답

응답 값 샘플

 

요청에 따른 응답 내역

항목 샘플 데이터
_id 1.0
상영관명 MMC 만경관 1관
연락처 257-2041
소재지도로명주소 대구광역시 중구 국채보상로 547 (종로 1가)
위도 35.8709275
경도 128.5904236
소재지우편번호  
소재지지번주소  

 

TheaterCell 클래스

import UIKit

class TheaterCell: UITableViewCell {
    
    // 상영관명
    @IBOutlet var name: UILabel!
    // 연락처
    @IBOutlet var tel: UILabel!
    // 주소
    @IBOutlet var addr: UILabel!
}

 

TheaterListController 클래스

API를 호출하고 영화관 정보를 읽어온다.

import UIKit

class TheaterListController: UITableViewController {
    
    // API를 통해 불러온 데이터를 저장할 배열 변수
    var list = [NSDictionary]()
    // 읽어올 데이터의 시작위치
    var startPoint = 0
    
    override func viewDidLoad() {
        // API를 호출한다.
        self.callTheaterAPI()
    }
    
    func callTheaterAPI() {
        
        // 1. URL을 구성하기 위한 상수값을 선언한다.
        let requestURI = "http://swiftapi.rubypaper.co.kr:2029/theater/list" // API 요청 주소
        let sList = 100 // 불러올 데이터 개수
        let type = "json" // 데이터 형식
        
        // 2. 인자값들을 모아 URL 객체로 정의한다.
        let urlObj = URL(string: "\(requestURI)?s_page=\(self.startPoint)&s_list=\(sList)&type=\(type)")
        
        do {
            // 3. NSString 객체를 이용하여 API를 호출하고 그 결과값을 인코딩된 문자열로 받아온다.
            let stringdata = try NSString(contentsOf: urlObj!, encoding: 0x80_000_422)
            
            // 4. 문자열로 받은 데이터를 UTF-8로 인코딩처리한 Data로 변환한다.
            let encdata = stringdata.data(using: String.Encoding.utf8.rawValue)
            
            do {
                // 5. Data 객체를 파싱하여 NSArray 객체로 변환한다.
                let apiArray = try JSONSerialization.jsonObject(with: encdata!, options: []) as? NSArray
                
                // 6. 읽어온 데이터를 순회하면서 self.list 배열에 추가한다
                for obj in apiArray! {
                    self.list.append(obj as! NSDictionary)
                }
                
            } catch {
                // 경고창 형식으로 오류 메시지를 표시해준다.
                let alert = UIAlertController(title: "실패",
                                              message: "데이터 분석이 실패하였습니다",
                                              preferredStyle: .alert)
                
                alert.addAction(UIAlertAction(title: "확인", style: .cancel))
                self.present(alert, animated: false)
            }
            // 7. 읽어와야 할 다음 페이지의 데이터 시작 위치를 구해 저장해둔다.
            self.startPoint += sList
            
        } catch {
            // 경고창 형식으로 오류 메시지를 표시해준다.
            let alert = UIAlertController(title: "실패",
                                          message: "데이터를 불러오는데 실패하였습니다",
                                          preferredStyle: .alert)
            
            alert.addAction(UIAlertAction(title: "확인", style: .cancel))
            self.present(alert, animated: false)
        }
    }
}

 

테이블 목록 구현

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.list.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    // self.list 배열에서 행에 맞는 데이터를 꺼냄
    let obj = self.list[indexPath.row]
    
    // 재사용 큐로부터 tCell 식별자에 맞는 셀 객체를 전달받음
    let cell = tableView.dequeueReusableCell(withIdentifier: "tCell") as! TheaterCell
    
    cell.name?.text = obj["상영관명"] as? String
    cell.tel?.text = obj["연락처"] as? String
    cell.addr?.text = obj["소재지도로명주소"] as? String
    
    return cell
}

 

 

 

 

 

 

 

'iOS > Swift' 카테고리의 다른 글

DispatchQueue 특징  (0) 2021.09.05
비동기에서의 NSLock() 간단 비교  (0) 2021.09.05
12.2.2. 영화관 정보 API  (0) 2021.09.02
이미지 비동기 처리하기  (0) 2021.08.14
뷰 컨트롤러 직접 호출에 의한 화면 전환  (0) 2021.08.09

- 문제 링크

https://programmers.co.kr/learn/courses/30/lessons/77484

 

코딩테스트 연습 - 로또의 최고 순위와 최저 순위

로또 6/45(이하 '로또'로 표기)는 1부터 45까지의 숫자 중 6개를 찍어서 맞히는 대표적인 복권입니다. 아래는 로또의 순위를 정하는 방식입니다. 1 순위 당첨 내용 1 6개 번호가 모두 일치 2 5개 번호

programmers.co.kr

난이도: Level 1

 

- 제출 답안

import Foundation

func rankingBy(_ win: Int) -> Int {
    
    switch win {
    case 6: return 1
    case 5: return 2
    case 4: return 3
    case 3: return 4
    case 2: return 5
    default: return 6
    }
}

func solution(_ lottos:[Int], _ win_nums:[Int]) -> [Int] {
    let low = lottos.filter( win_nums.contains ).count
    let hidden = lottos.filter{ $0 == 0 }.count
    let high = low + hidden
    
    let lottoResult = [high, low].map{ rankingBy($0)}
    
    return lottoResult
}

 

- 풀이

먼저 이 문제는 lottos 와 win_nums의 관계, 그리고 점수 구성이 어떻게 되는지의 알고리즘이 중요합니다.

최저 순위(low)는 숨겨진 숫자(hidden -> 0)가 전부 틀리다면 0을 제외한 숫자 중 win_nums에 해당하는 숫자 만큼 맞힌 숫자가 됩니다.

최저 순위는 0을 생각할 필요가 없는거죠.

반면 최고 순위(high)은 0이 전부 맞는다는 가정으로 hidden과 low가 합친 숫자 만큼 맞힌 숫자가 만들어 집니다.

 

그리고 rankingBy 함수에 switch를 이용해서 맞힌 숫자를 순위로 변환할 수 있는 함수를 만들었습니다.

 

마지막으로 lottoResult 변수에 각 맞힌 숫자를 순위로 변환하면서 최고, 최저 순위 배열이 만들어졌습니다.

 

'iOS > 알고리즘' 카테고리의 다른 글

[프로그래머스] 크레인 인형뽑기 게임  (0) 2021.10.04
[프로그래머스] 체육복  (0) 2021.09.21
[프로그래머스]기능개발  (0) 2021.08.23
[프로그래머스]모의고사  (0) 2021.08.22
[백준]1789번: 수들의 합  (0) 2021.08.15

- 문제 링크

https://programmers.co.kr/learn/courses/30/lessons/42586

 

코딩테스트 연습 - 기능개발

프로그래머스 팀에서는 기능 개선 작업을 수행 중입니다. 각 기능은 진도가 100%일 때 서비스에 반영할 수 있습니다. 또, 각 기능의 개발속도는 모두 다르기 때문에 뒤에 있는 기능이 앞에 있는

programmers.co.kr

난이도: Level 2

 

- 문제

/**
 문제 설명
 프로그래머스 팀에서는 기능 개선 작업을 수행 중입니다. 각 기능은 진도가 100%일 때 서비스에 반영할 수 있습니다.

 또, 각 기능의 개발속도는 모두 다르기 때문에 뒤에 있는 기능이 앞에 있는 기능보다 먼저 개발될 수 있고, 이때 뒤에 있는 기능은 앞에 있는 기능이 배포될 때 함께 배포됩니다.

 먼저 배포되어야 하는 순서대로 작업의 진도가 적힌 정수 배열 progresses와 각 작업의 개발 속도가 적힌 정수 배열 speeds가 주어질 때 각 배포마다 몇 개의 기능이 배포되는지를 return 하도록 solution 함수를 완성하세요.

 제한 사항
 작업의 개수(progresses, speeds배열의 길이)는 100개 이하입니다.
 작업 진도는 100 미만의 자연수입니다.
 작업 속도는 100 이하의 자연수입니다.
 배포는 하루에 한 번만 할 수 있으며, 하루의 끝에 이루어진다고 가정합니다. 예를 들어 진도율이 95%인 작업의 개발 속도가 하루에 4%라면 배포는 2일 뒤에 이루어집니다.
 입출력 예
 progresses    speeds    return
 [93, 30, 55]    [1, 30, 5]    [2, 1]
 [95, 90, 99, 99, 80, 99]    [1, 1, 1, 1, 1, 1]    [1, 3, 2]
 입출력 예 설명
 입출력 예 #1
 첫 번째 기능은 93% 완료되어 있고 하루에 1%씩 작업이 가능하므로 7일간 작업 후 배포가 가능합니다.
 두 번째 기능은 30%가 완료되어 있고 하루에 30%씩 작업이 가능하므로 3일간 작업 후 배포가 가능합니다. 하지만 이전 첫 번째 기능이 아직 완성된 상태가 아니기 때문에 첫 번째 기능이 배포되는 7일째 배포됩니다.
 세 번째 기능은 55%가 완료되어 있고 하루에 5%씩 작업이 가능하므로 9일간 작업 후 배포가 가능합니다.

 따라서 7일째에 2개의 기능, 9일째에 1개의 기능이 배포됩니다.

 입출력 예 #2
 모든 기능이 하루에 1%씩 작업이 가능하므로, 작업이 끝나기까지 남은 일수는 각각 5일, 10일, 1일, 1일, 20일, 1일입니다. 어떤 기능이 먼저 완성되었더라도 앞에 있는 모든 기능이 완성되지 않으면 배포가 불가능합니다.

 따라서 5일째에 1개의 기능, 10일째에 3개의 기능, 20일째에 2개의 기능이 배포됩니다.
 */

 

- 제출한 답안

import Foundation

func solution(_ progresses:[Int], _ speeds:[Int]) -> [Int] {
    var completionDate = [Int]()

    for (i, value) in progresses.enumerated() {
        completionDate.append((100 - value) / speeds[i])
        if (100 - value) % speeds[i] != 0 {
            completionDate[i] += 1
        }
    }

    var release = [Int]()
    var releases = [[Int]]()

    for date in completionDate {
        if date > completionDate.first! {
            releases.append(release)
            release = [Int]()
            completionDate.removeSubrange(0..<(completionDate.firstIndex(of: date)!))
            release.append(completionDate[0])
        } else {
            release.append(date)
        }
        
        if release == completionDate {
            releases.append(release)
        }
    }

    return releases.map { $0.count }
}

 

 

문제 링크

https://programmers.co.kr/learn/courses/30/lessons/42840

 

코딩테스트 연습 - 모의고사

수포자는 수학을 포기한 사람의 준말입니다. 수포자 삼인방은 모의고사에 수학 문제를 전부 찍으려 합니다. 수포자는 1번 문제부터 마지막 문제까지 다음과 같이 찍습니다. 1번 수포자가 찍는

programmers.co.kr

난이도: Level 1

문제

/**
 문제 설명
 수포자는 수학을 포기한 사람의 준말입니다. 수포자 삼인방은 모의고사에 수학 문제를 전부 찍으려 합니다. 수포자는 1번 문제부터 마지막 문제까지 다음과 같이 찍습니다.

 1번 수포자가 찍는 방식: 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, ...
 2번 수포자가 찍는 방식: 2, 1, 2, 3, 2, 4, 2, 5, 2, 1, 2, 3, 2, 4, 2, 5, ...
 3번 수포자가 찍는 방식: 3, 3, 1, 1, 2, 2, 4, 4, 5, 5, 3, 3, 1, 1, 2, 2, 4, 4, 5, 5, ...

 1번 문제부터 마지막 문제까지의 정답이 순서대로 들은 배열 answers가 주어졌을 때, 가장 많은 문제를 맞힌 사람이 누구인지 배열에 담아 return 하도록 solution 함수를 작성해주세요.

 제한 조건
 시험은 최대 10,000 문제로 구성되어있습니다.
 문제의 정답은 1, 2, 3, 4, 5중 하나입니다.
 가장 높은 점수를 받은 사람이 여럿일 경우, return하는 값을 오름차순 정렬해주세요.
 입출력 예
 answers    return
 [1,2,3,4,5]    [1]
 [1,3,2,4,2]    [1,2,3]
 입출력 예 설명
 입출력 예 #1

 수포자 1은 모든 문제를 맞혔습니다.
 수포자 2는 모든 문제를 틀렸습니다.
 수포자 3은 모든 문제를 틀렸습니다.
 따라서 가장 문제를 많이 맞힌 사람은 수포자 1입니다.

 입출력 예 #2

 모든 사람이 2문제씩을 맞췄습니다.
 */

제출한 답안

import Foundation

func solution(_ answers:[Int]) -> [Int] {

    let onePattern = [1, 2, 3, 4, 5]
    var oneCount = 0

    let twoPattern = [2, 1, 2, 3, 2, 4, 2, 5]
    var twoCount = 0

    let threePattern = [3, 3, 1, 1, 2, 2, 4, 4, 5, 5]
    var threeCount = 0

    for i in 0...(answers.count - 1) {
        if answers[i] == onePattern[i % 5] {
            oneCount += 1
        }

        if answers[i] == twoPattern[i % 8] {
            twoCount += 1
        }

        if answers[i] == threePattern[i % 10] {
            threeCount += 1
        }
    }

    print(oneCount)
    print(twoCount)
    print(threeCount)

    var rankingDic = [Int: Int]()

    rankingDic[1] = oneCount
    rankingDic[2] = twoCount
    rankingDic[3] = threeCount

    let rankingSort = rankingDic.sorted{ $0.key < $1.key }.filter{ $0.value == (rankingDic.values.max()) }.map { $0.key }
    print(rankingSort)

    return rankingSort
}

풀이

처음에는 패턴을 통해 answers와 같은 크기의 배열을 생성한 뒤에 배열에서 다시 answers와 비교하였는데 배열 생성할 필요가 없다는걸 알게되어 패턴에서 바로 비교하였습니다.

그리고 패턴 비교를 통해 맞힌 개수(oneCount)를 계산했습니다.

여기까지는 쉬웠는데 그 뒤가 어려웠어요.

 

- 수포자 순서 뽑는 과정

1, 2, 3번 수포자에 각각 Count를 할당하고 그 뒤에 Count 높은 순으로 정렬하고 제일 높은 값과 같이 않으면 삭제한 뒤 수포자 순서대로 재정렬을 해야겠다는 생각을 했습니다.

그러나 Count 높은 순으로 정렬을 한 뒤 다시 수포자 순서대로 정렬을 하려니 도저히 떠오르지 않아 몇시간을 헤매다가 결국 사이트 답을 보았습니다.

답을 보니 sorted, filter, map 을 같이 쓰네요.

정렬을 한 뒤 값이 같다면 다시 재정렬이 아니라, 수포자 순으로 정렬을 시킨 뒤 제일 큰 값과 같은 값만 다시 담아 오는 거였습니다.

 

sorted 로 수포자 순으로 정렬을 시킨 뒤, 배열에서 가장 높은 값과 같은 값만 남겨주고 이 배열이 딕셔너리로 되어있기 때문에 배열로 반환을 해주기 위해 수포자 키 값만 map에 담아 배열을 만들어줍니다.

sorted로 정렬을 시키고 filter로 큰 값만 가져오는게 핵심이였습니다.

답안 수정

import Foundation

func solution(_ answers:[Int]) -> [Int] {

    let patterns = (
        a: [1, 2, 3, 4, 5],
        b: [2, 1, 2, 3, 2, 4, 2, 5],
        c: [3, 3, 1, 1, 2, 2, 4, 4, 5, 5]
    )

    var ranking = [1: 0, 2: 0, 3: 0]

    for (i, v) in answers.enumerated() {
        if v == patterns.a[i % 5] {
            ranking[1]! += 1
        }
        
        if v == patterns.b[i % 8] {
            ranking[2]! += 1
        }
        
        if v == patterns.c[i % 10] {
            ranking[3]! += 1
        }
    }

    let rankingSort = ranking.sorted{ $0.key < $1.key }.filter{ $0.value == (ranking.values.max()) }.map { $0.key }

    return rankingSort
}

각 pattern 을 patterns로 묶고 answers.enumerated() 를 통해 인덱스와 값을 활용했습니다.

import UIKit

// 1. 후행 클로저: 함수의 매개변수 마지막으로 전달되는 클로저는 후행클로저(trailing closure)로 함수 밖에 구현 가능
// 2. 반환타입 생략: 컴파일러가 클로저의 타입을 유추할 수 있는 경우 매개변수, 반환 타입을 생략 가능
// 3. 단축 인자 이름: 전달인자의 이름이 굳이 필요없고, 컴파일러가 타입을 유추할 수 있는 경우 축약된 전달인자 이름($0, $1, $2 ...)을 사용 가능
// 4. 암시적 반환 표현: 반환 값이 있는 경우, 암시적으로 클로저의 맨 마지막 줄은 return 키워드를 생략하더라도 반환 값으로 취급


/// 기본 클로저 표현
// 클로저를 매개변수로 갖는 함수 calcaulated(a: b: method:)와 결과값을 저장할 변수 result 선언
func calculate(a: Int, b: Int, method: (Int, Int) -> Int) -> Int {
    return method(a, b)
}

var result: Int

/// 1. 후행 클로저
// 클로저가 함수의 마지막 전달인자일때, 마지막 매개변수 이름을 생략한 후 함수 소괄호 외부에 클로저를 구현 가능
result = calculate(a: 10, b: 10) { (left: Int, right: Int) -> Int in
    return left + right
}

print(result) // 20


/// 2. 반환타입 생략
// calculate(a:b:method:) 함수의 method 매개변수는 Int 타입을 반환할 것이라는 사실을 컴파일러도 알기 때문에 굳이 클로저에서 반환타입을 명시해 주지 않아도 된다. 대신 in 키워드는 생략 불가
result = calculate(a: 10, b: 10, method: { (left: Int, right: Int) in
    return left + right
})

print(result) // 20


/// 3. 단축 인자이름
// 클로저의 매개변수 이름이 굳이 불필요하다면 단축 인자이름을 활용 가능.
// 단축 인자이름은 클로저의 매개변수의 순서대로 $0, $1, $2 ... 처럼 표현
result = calculate(a: 10, b: 10, method: {
    return $0 + $1
})

print(result) // 20

// 당연히 후행 클로저와 함께 사용 가능
result = calculate(a: 10, b: 10) {
    return $0 + $1
}

print(result) // 20


/// 4. 암시적 반환 표현
// 클로저가 반환하는 값이 있다면 클로저의 마지막 줄의 결과값은 암시적으로 반환값으로 취급
result = calculate(a: 10, b: 10){
    $0 + $1
}

print(result) // 20

// 간결하게 한 줄로 표현 가능
result = calculate(a: 10, b: 10) { $0 + $1}

print(result) // 20


/// 축약 전과 후 비교
// 축약 전
result = calculate(a: 10, b: 10, method: { (left: Int, right: Int) -> Int in
    return left + right
})

// 축약 후
result = calculate(a: 10, b: 10) { $0 + $1 }

print(result) // 20

// 너무 축약된 코드는 타인이 보거나, 시간이 지난 뒤에 볼 때 명시성이 떨어질 수 있으므로 적정선에서 축약

'iOS > 문법' 카테고리의 다른 글

클로저 기본  (0) 2021.08.19
변수 상수  (0) 2021.08.09
import UIKit

/// 1. 클로저
// 실행가능한 코드 블럭
// 함수와 다르게 이름정의는 필요하지 않지만, 매개변수 전달과 반환 값이 존재
// 함수는 이름이 있는 클로저
// 일급객체로 전달인자, 변수, 상수 등에 저장 및 전달 가능


/// 2. 기본 클로저 문법
// 클로저는 중괄호 {}로 감싼다
// 괄호를 이용해 파라미터를 정의
// -> 을 이용해 반환 타입을 명시
// "in" 키워드를 이용해 실행 코드와 분리
/*
 {(매개변수 목록) -> 반환타입 in
    실행 코드
 }
 */


/// 3. 클로저 사용
// sum이라는 상수에 클로저를 할당
let sum: (Int, Int) -> Int /* 클로저 타입 표현 */ = {(a: Int, b: Int) in
    return a + b
}

let sumResult: Int = sum(1, 2)
print(sumResult) // 3


/// 4. 함수의 전달인자로서의 클로저
// 클로저는 주로 함수의 전달인자로 많이 사용
// 함수 내부에서 원하는 코드블럭을 실행
let add: (Int, Int) -> Int
add = {(a: Int, b: Int) in
    return a + b
}

let substract: (Int, Int) -> Int
substract = {(a: Int, b: Int) in
    return a - b
}

let divide: (Int, Int) -> Int
divide = {(a: Int, b: Int) in
    return a / b
}

func calculate(a: Int, b: Int, method: (Int, Int) -> Int) -> Int {
    return method(a, b)
}

var calculated: Int

calculated = calculate(a: 50, b: 10, method: add)

print(calculated) // 60

calculated = calculate(a: 50, b: 10, method: substract)

print(calculated) // 40

calculated = calculate(a: 50, b: 10, method: divide)

print(calculated) // 5

// 따로 클로저를 상수/변수에 넣어 전달하지 않고,
// 함수를 호출할 때 클로저를 작성하여 전달 가능

calculated = calculate(a: 50, b: 10, method: {(left: Int, right: Int) -> Int in
    return left * right
})

print(calculated) // 500

'iOS > 문법' 카테고리의 다른 글

클로저 고급 - 다양한 클로저 표현  (0) 2021.08.19
변수 상수  (0) 2021.08.09

원문 링크:

https://pilgwon.github.io/blog/2017/09/26/RxSwift-By-Examples-1-The-Basics.html

 

예제로 시작하는 RxSwift #1 - 기초

RXSWIFT BY EXAMPLES #1 – THE BASICS.

pilgwon.github.io

버전이 달라서 그런지 속성이 약간 다릅니다.

기존 코드는 swift 3 이어서 빌드가 안됩니다.

searchBar
  .rx.text // RxCocoa의 Observable 속성
  .orEmpty // 옵셔널이 아니도록 만듭니다.
  .debounce(RxTimeInterval.milliseconds(500), scheduler: MainScheduler.instance)
  .distinctUntilChanged()
  .subscribe(onNext: { [unowned self] query in
  self.shownCities = self.allCities.filter { $0.hasPrefix(query) }
  self.tableView.reloadData()
  })
  .disposed(by: disposeBag)

.debounce .disposed 부분이 차이가 있습니다.

자세한 내용은 원문을 참고해주세요.

제가 만들어본 소스 git 링크: https://github.com/SungKihun/CitySearcher.git

출처: https://www.youtube.com/watch?v=hkRvC0_LnZk 

MVC, MVP, MVVM 차이점

영상은 MVC, MVP, MVVM 의 차이점에 대한 영상입니다.

'iOS > 기술' 카테고리의 다른 글

코코아팟 출시하기  (2) 2021.09.28
REST API 란?  (0) 2021.08.17
React Native 란?  (0) 2021.08.17

[출처] [IT지식/API] REST API란? (feat. HTTP 응답 코드)|작성자 Jaeeun

 

1. REST?

Representational state transfer의 약자로, 백엔드와 클라이언트의 커뮤니케이션 방식을 의미한다.

특정 기술을 의미하는 것이 아니라, HTTP로 통신할 때 가장 적합한 방식을 말하는 것으로

URL을 통해 자원을 명시하고, HTTP Method를 통해 해당 자원에 대한 행위를 정의한다.

즉, 소프트웨어가 관리하는 데이터, 이미지 등의 정보를 주고 받는 가장 적합한 방법인 것이다.

다른 말로는 RESTful Web services라고도 불린다.

2. REST의 구성요소

1) 자원(URL)

자원은 데이터를 의미하며, 다른 말로는 리소스라고도 불린다.

그리고 이러한 리소스는 URI(URL)을 통해서 표현된다.

출처 : https://www.youtube.com/watch?v=PmY3dWcCxXI

이때, 여러 개의 데이터를 한 번에 식별하고 싶다면 데이터를 묶음의 URI를 사용하는데

이를 Collection이라고 부른다.

그리고 컬렉션 안에 있는 각각의 데이터를 Element라고 부른다.

즉, 컬렉션은 복수의 형태를 띠며 Element가 모여있는 것을 의미한다.

REST API는 URL을 보면, 어떤 자원인지 쉽게 파악할 수 있다(슬래시로 구분).

2) 행위(HTTP Method)

위의 리소스는 그저 데이터가 존재하는 것이기 때문에 어떠한 작업도 하지 못한다.

때문에 반드시 '행위'를 통해 데이터를 전달하거나 받아와야 한다.

행위의 방법에는 'POST, GET, PUT, DELETE' 4가지가 존재하며, 이를 Method라고 부른다.

HTTP REST Create → POST(생성) Read → GET(조회) Update → PUT(전체 수정) Delete → DELETE(삭제)

또한, REST API는 HTTP를 이용한 것이기 때문에 HTTP Method를 사용한다.

3) 자원의 형태 (JSON)

클라이언트가 HTTP Method를 통해서 데이터 조작을 요청하면, 서버가 적절한 응답을 보내게 된다.

이때 하나의 자원은 JSON, XML, TEXT 등 여러 형태로 표현된다.

보통은 JSON, XML을 통해 데이터를 주고 받는다.

3. REST API와 RESTFul

REST API는 REST 기반으로 서비스 API를 구현한 것을 의미한다.

1) REST API 설계 규칙

REST API를 올바르게 설계하기 위해서는 지켜야하는 몇가지 규칙이 있다.

URI는 동사보다는 명사를, 대문자보다는 소문자를 사용해야 한다. ② 행위를 포함하지 않는다.언더바(_) 대신 하이픈(-)을 사용한다. ④ 파일 확장자(.jgp 등)URI에 포함하지 않는다. ⑤ 마지막에 슬래시(/)를 포함하지 않는다. → 슬래시 구분자는 계층 관계를 나타낼때 사용하므로 맨 마지막에는 사용하지 않는 것이 좋다.

ex)

//행위를 포함하지 않는다. GET resource/delete/1 //X, uri에 delete 포함 DELETE resource/1 //O

2) RESTFul

RESTFul은 REST API를 제공하는 웹 서비스를 의미한다.

4. HTTP 응답 코드 의미

1) 성공

상태코드 의미
200 클라이언트 요청을 정상적으로 수행
201 클라이언트가 리소스 생성 요청, 성공적으로 생성됨(POST)

2) 실패

상태코드 의미
400 클라이언트 요청에서 문제가 발생했을 때
401 클라이언트가 인증되지 않은 상태에서 보호된 리소스를 요청했을 때
403 응답하고 싶지 않은 리소스를 클라이언트가 요청했을 때
405 클라이언트가 요청한 리소스에서 사용 불가능한 Method를 이용했을 때
상태코드 의미
301 리소스 URI가 변경되었을 때
상태코드 의미
500 서버에 문제가 있을 때

 

 

'iOS > 기술' 카테고리의 다른 글

코코아팟 출시하기  (2) 2021.09.28
MVVM, Reactive, RxSwift  (0) 2021.08.17
React Native 란?  (0) 2021.08.17

출처: https://blog.naver.com/dpszeagal33/222399097211

출처: https://blog.naver.com/inflearn/222341617669

탄생

React Native는 페이스북에서 2015년에 출시한 프레임워크입니다.

 

환경

iOS 앱과 안드로이드 앱을 모두 자바스크립트 환경에서 네이티브로 개발할 수 있는 환경입니다. 크로스 플랫폼 앱이지요.

때문에 node.js, iOS, 안드로이드를 위한 다양한 설정 과정이 필요합니다.

iOS 앱의 개발을 위해서는 OS X가 필수적입니다. 기술적으로 보자면 Android 앱의 개발은 플랫폼과는 별도로 독립적일 수 있지만 iOS 앱의 개발은 OS X 전용으로 개발이 되있습니다. 그래서 React Native로 앱을 개발하기 위해서는 맥 환경을 사용해야 합니다.

 

특징

첫번째, 자바스크립트 기반

자바스크립트 라이브러리의 한 종류인 리액트와 동일한 문법, 개념을 공유하고 있어요. 그래서 자바스크립트를 다룰 줄 아는 분이라면, 특히 리액트 라이브러리를 다룬 적이 있다면 쉽게 배울 수 있습니다. 페북, 인스타그램 앱의 일부를 리액트 네이티브로 제작하고 있어요.

 

두번째, 오픈소스

React Native는 오픈 소스로 커뮤니티가 활성화되어 있습니다. 모르는 정보가 있다면 블로그에서 정보를 찾아 볼수 있어서 이런 장점 덕분에 React Native는 크로스 플랫폼 개발의 한 축을 담당하고 있습니다.

'iOS > 기술' 카테고리의 다른 글

코코아팟 출시하기  (2) 2021.09.28
MVVM, Reactive, RxSwift  (0) 2021.08.17
REST API 란?  (0) 2021.08.17

문제 링크

https://www.acmicpc.net/problem/1789

 

1789번: 수들의 합

첫째 줄에 자연수 S(1 ≤ S ≤ 4,294,967,295)가 주어진다.

www.acmicpc.net

문제

/**
문제
서로 다른 N개의 자연수의 합이 S라고 한다. S를 알 때, 자연수 N의 최댓값은 얼마일까?

입력
첫째 줄에 자연수 S(1 ≤ S ≤ 4,294,967,295)가 주어진다.

출력
첫째 줄에 자연수 N의 최댓값을 출력한다.

예제 입력 1
200
예제 출력 1
19
 */

제출한 답안

import Foundation

func maximum(max S: Int) -> Int {
    var sum = 0
    var N = 0
    
    for i in 1... {
        sum += i
        guard sum <= S else {
            break
        }
        N = i
    }
    return N
}
let S = Int(readLine()!)!

print(maximum(max: S))

풀이

처음에 읽어보았을때 N의 최댓값은 결국 제일 작은 숫자인 1부터 하나씩 증가한 값을 더해가는 경우의 최대값이라는 생각이 들었습니다.

1부터 하나씩 더해가려면 for문 1... 을 활용하면 좋을거 같았어요.

특정 조건일때 멈추려면 java라면 if break 가 있겠지만, swift는 특정 조건이 아닐때만 멈추면 되니 guard문이 더 괜찮았습니다.

더하고 나서 멈추려니 200입력에서 20이 출력되는 즉, sum이 200초과한 상태에서 S와 비교가 되어서 어떻게 하면 전 상태의 값을 기억할 수 있을까 생각해보았습니다.

해결법은 'i를 sum에 더한 다음에 i값을 N에 따로 저장하되 비교하기 전에 저장해 놓자' 였습니다. 그래서 guard문을 N 전에 놓았습니다.

https://piquant-oyster-f84.notion.site/10-1-2-a2049d2d81134eb69ba0f040daee98ec

 

10.1.2. 이미지 비동기 처리하기

비동기(Asynchronize) 처리 기법

piquant-oyster-f84.notion.site

 

'iOS > Swift' 카테고리의 다른 글

DispatchQueue 특징  (0) 2021.09.05
비동기에서의 NSLock() 간단 비교  (0) 2021.09.05
12.2.2. 영화관 정보 API  (0) 2021.09.02
12.3. 영화관 목록 화면 구현하기  (0) 2021.09.02
뷰 컨트롤러 직접 호출에 의한 화면 전환  (0) 2021.08.09

https://piquant-oyster-f84.notion.site/Git-1b1a15117a434972b1c4d11d8c775593

 

Git 용어 정리

Git: 깃이라고 읽고, 버전 관리 시스템이다.

piquant-oyster-f84.notion.site

 

https://piquant-oyster-f84.notion.site/04-GitHub-c3efa2e19129406da2dfeddb93476cac

 

04. GitHub 원격저장소의 커밋을 로컬저장소에 내려받기

문어의 로컬저장소를 만들어 지정하고 고양이의 원격저장소에 올라가 있는 커밋을 내려받기

piquant-oyster-f84.notion.site

 

'Git' 카테고리의 다른 글

Git 용어 정리  (0) 2021.08.14
GitHub 원격저장소에 커밋 올리기  (0) 2021.08.14
로컬 저장소에서 커밋 관리하기  (0) 2021.08.14

https://piquant-oyster-f84.notion.site/03-GitHub-d349bd8750244ab9a15acd8309b3e2ea

 

03. GitHub 원격저장소에 커밋 올리기

원격저장소 만들기

piquant-oyster-f84.notion.site

 

'Git' 카테고리의 다른 글

Git 용어 정리  (0) 2021.08.14
GitHub 원격저장소의 커밋을 로컬저장소에 내려받기  (0) 2021.08.14
로컬 저장소에서 커밋 관리하기  (0) 2021.08.14

https://piquant-oyster-f84.notion.site/02-52dadfb6d72743bca4430af70c19d0ca

 

02. 로컬저장소에서 커밋 관리하기

git 확인하기

piquant-oyster-f84.notion.site

 

'Git' 카테고리의 다른 글

Git 용어 정리  (0) 2021.08.14
GitHub 원격저장소의 커밋을 로컬저장소에 내려받기  (0) 2021.08.14
GitHub 원격저장소에 커밋 올리기  (0) 2021.08.14

사이트링크:https://hyerios.tistory.com/8

 

 

iOS 기존의 프로젝트에 코어데이터 추가하기

대부분 코어데이터를 프로젝트 파일을 생성할 때 체크박스를 눌러 코어데이터를 추가합니다. 그런데 저는 프로젝트를 생성하고 어느정도 작업이 진행되고 갑자기 코어데이터를 사용하기로

hyerios.tistory.com

메모앱 만들기 공부하는데 처음 생성시에 코어데이터 체크를 안해서 추가하는 방법을 찾아보았습니다.

'iOS > 문제 해결' 카테고리의 다른 글

p12로 개발 인증서 내보내기  (3) 2021.11.05
TableViewCell 의 textLabel 대체  (0) 2021.10.22

+ Recent posts