본문 바로가기
computing

20260519_iOS11

by greentworkshop 2026. 5. 19.

위 이미지에서 한 문제 정도 출제
어떤 유형이 있는지 정도만 알면 됨

 

 

Constraint(제약)
제약은 뷰의 크기와 위치를 결정하는 규칙. 뷰의 너비, 높이, 상단, 하단, 좌측, 우측 간격 등을 제어

  •   SuperviewSubview
    •   Superview는 다른 뷰를 포함하는 뷰, SubviewSuperview 내에 위치한 뷰
    •   제약은 주로 SuperviewSubview 간에 설정
  •   Safe Area
    •   뷰의 콘텐츠가 안전하게 표시될 수 있는 영역.
    •   일반적으로상태바,네비게이션바,탭바등과같은시스템UI를 고려하여설정
  •   AlignmentPin 메뉴

Resolve Auto Layout Issues

Storyboard의 하단에 위치한 메뉴로 제약을 추가하는 데 사용

Align

  •   Alignment 메뉴를 사용하면 뷰의 정렬을 설정
  •   Pin 메뉴를 사용하면 뷰간의 거리, 뷰의 너비와 높이 등을 설정

Pin

Stack View

 Content Hugging 및 Content Compression Resistance Priority

  •   뷰의 크기가 내용에 어떻게 맞춰져야 하는지를 결정
  •   Content Hugging : 내 크기를 더 크게 늘리고 싶지 않아!
  •   Content Compression Resistance : 내 크기를 더 줄이고 싶지 않아!

 

빨간색으로 강조된 부분은 시험에 무조건 나옴

 

오토레이아웃을 조절하는 사이즈 인스펙터

constraint가 부족하거나 충돌할 경우

constraint가 부족할 때(Ambiguous Layouts) Missing Constraints(부족)
Constraints Ambiguity(모호)

constraint가 충돌할 때(Unsatisfiable Layouts)

Conflicting(충돌) Constraints

우선순위(priority) 지정

  •   1000이 가장 높은 우선순위
  •   충돌 시 priority 값이 작은 쪽은 오토레이아웃에서 반영되지 않음

조건 1
A.width = 0.3 * Superview.width (priority = 750)
조건 2
A.width >= 150 (priority =
1000)

 

 

우선순위

콘텐츠 허깅 vs 컴프레션 저항
직접 정한게 우선순위 더 높음

 

stackview에는 두 가지 종류

  • 세로 방향으로 묶어주는 것이 Vertical Stack View
  • 가로 방향으로 묶어주는 것이 Horizontal Stack View

스택뷰는 핵심

Axis

가로(Horizontal) 스택 뷰인지, 세로(Vertical) 스택 뷰인지?

Alignment 하위뷰의위치정렬

Distribution 하위뷰의크기배분

Spacing 하위뷰사이간격

 

 

완성본 소스

//
//  ViewController.swift
//  MovieCjh
//
//  Created by Induk-cs on 2026/04/28.
//

import UIKit

//let name = ["살목지","란 12.3","짱구","프로젝트 헤일메리","왕과 사는 남자","내 이름은","리 크로닌의 미이라","기동전사 건담: 섬광의 하사웨이 키르케의 마녀","르누아르","마녀배달부 키키"]

struct MovieData : Codable {
    let boxOfficeResult : BoxOfficeResult
}
struct BoxOfficeResult : Codable {
    let dailyBoxOfficeList : [DailyBoxOfficeList] }
struct DailyBoxOfficeList : Codable {
    let movieNm : String
    let audiCnt : String
    let audiAcc : String
    let rank : String
}


class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        //print(indexPath.description)//화면에서 클릭하면 어떤 로우의 어떤 섹션을 선택했는지 출력됨
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
     let cell = tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath) as! MyTableViewCell
     guard let mRank = movieData?.boxOfficeResult.dailyBoxOfficeList[indexPath.row].rank else {return UITableViewCell()}
     guard let mName = movieData?.boxOfficeResult.dailyBoxOfficeList[indexPath.row].movieNm else {return UITableViewCell()}
     cell.movieName.text = "[\(mRank)위] \(mName)"
     if let aCnt = movieData?.boxOfficeResult.dailyBoxOfficeList[indexPath.row].audiCnt {
      let numF = NumberFormatter()
      numF.numberStyle = .decimal
      let aCount = Int(aCnt)!
      let result = numF.string(for: aCount)!+"명"
      cell.audiCount.text = "어제 : \(result)"
     }
     if let aAcc = movieData?.boxOfficeResult.dailyBoxOfficeList[indexPath.row].audiAcc {
      let numF = NumberFormatter()
      numF.numberStyle = .decimal
      let aAcc1 = Int(aAcc)!
      let result = numF.string(for: aAcc1)!+"명"
      cell.audiAccumulate.text = "누적 : \(result)"
     }
     return cell
    }
    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return "🍿박스오피스(영화진흥위원회제공:"+makeYesterdayString()+")🍿"
    }
    func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
        return "made by CJH"
    }
    
    @IBOutlet weak var table: UITableView!
    var movieData : MovieData?
    //전날의 영화 순위로 바꾸기, 링크에서 날짜부분을 변수로 설정
    var movieURL = "https://kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList.json?key=b735d5397e2b621db6dda1700ae5beef&targetDt="
    override func viewDidLoad() {
        
        super.viewDidLoad()
        table.delegate = self
        table.dataSource = self
        movieURL += makeYesterdayString()
        getData()
        // Do any additional setup after loading the view.
    }
    func makeYesterdayString() -> String {
        let y = Calendar.current.date(byAdding:.day, value : -1, to : Date())!
        let dateF = DateFormatter()
        dateF.dateFormat = "yyyyMMdd"
        let day = dateF.string(from: y)
        return day
    }
    func getData(){
        guard let url = URL(string: movieURL)else{return}
        let session = URLSession(configuration: .default)
        let task = session.dataTask(with: url) { data, response, error in
            
            if error != nil{ return}//만일 에러가 있다면 끝내버려
            guard let JSONdata = data else {return}
            let dataString = String(data: JSONdata, encoding: .utf8)
            print(JSONdata)
            //print(response!)
            //print(dataString)
            let decoder = JSONDecoder()
            do{
                let decodedData = try decoder.decode(MovieData.self, from: JSONdata)
                print(decodedData.boxOfficeResult.dailyBoxOfficeList[0].movieNm)
                self.movieData = decodedData
                DispatchQueue.main.async{
                    self.table.reloadData()
                }//클로저인경우 접근하려면 self써야 함, UI관련 소스는 main thread애서 처리해야 함
            }catch{
                print(error)
            }
        }
        task.resume() //4단계 >>> 3689 bytes
    }
}

출력 결과물

 

 

가끔 시험에 출제되는 소스

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath) as! MyTableViewCell
    
    cell.movieName.text = movieData?.boxOfficeResult.dailyBoxOfficeList[indexPath.row].movieNm
    
    if let aCnt = movieData?.boxOfficeResult.dailyBoxOfficeList[indexPath.row].audiCnt {
        let numF = NumberFormatter()
        numF.numberStyle = .decimal
        
        let count = Int(aCnt)!
        let result = numF.string(for: count)! + "명"
        
        cell.audiCount.text = "어제 : \(result)"
    }
    
    if let aAcc = movieData?.boxOfficeResult.dailyBoxOfficeList[indexPath.row].audiAcc {
        let numF = NumberFormatter()
        numF.numberStyle = .decimal
        
        let acc = Int(aAcc)!
        let result = numF.string(for: acc)! + "명"
        
        cell.audiAccumulate.text = "누적 : \(result)"
    }
    
    return cell
}

 

 

//코드설명

//
//  ViewController.swift
//  MovieCjh
//

import UIKit

// UIKit
// iOS 화면 구성(UI) 관련 기능을 사용하는 프레임워크



// MARK: - JSON 구조체 생성

// Codable
// JSON 데이터를 Swift 구조체로 자동 변환 가능하게 하는 프로토콜
// Decodable + Encodable 합쳐진 형태

// API의 최상위 JSON 구조
struct MovieData : Codable {

    // JSON의 boxOfficeResult 키와 매칭
    let boxOfficeResult : BoxOfficeResult
}



// boxOfficeResult 내부 구조
struct BoxOfficeResult : Codable {

    // dailyBoxOfficeList 배열 저장
    let dailyBoxOfficeList : [DailyBoxOfficeList]
}



// 영화 1개의 데이터를 저장하는 구조체
struct DailyBoxOfficeList : Codable {

    // let : 상수(값 변경 불가능)

    let movieNm : String     // 영화 제목
    let audiCnt : String     // 하루 관객수
    let audiAcc : String     // 누적 관객수
    let rank : String        // 영화 순위
}





// UIViewController 상속
// 화면 하나를 담당하는 클래스

// UITableViewDelegate
// 셀 선택 등 이벤트 처리

// UITableViewDataSource
// 테이블에 데이터 공급
class ViewController: UIViewController,
                      UITableViewDelegate,
                      UITableViewDataSource {



    // MARK: - 테이블 행 개수



    // 섹션(section)당 행(row) 개수 설정
    // 현재 박스오피스 10개 출력

    // section :
    // 테이블의 그룹 개념

    // Int 반환
    func tableView(_ tableView: UITableView,
                   numberOfRowsInSection section: Int)
    -> Int {

        return 10
    }



    // MARK: - 섹션 개수



    // 테이블의 섹션 개수
    func numberOfSections(in tableView: UITableView)
    -> Int {

        return 1
    }



    // MARK: - 셀 선택 이벤트



    // 셀 클릭 시 실행되는 함수
    func tableView(_ tableView: UITableView,
                   didSelectRowAt indexPath: IndexPath) {

        // indexPath.row
        // 클릭된 행 번호

        // indexPath.section
        // 클릭된 섹션 번호

        // print(indexPath.description)
    }



    // MARK: - 셀 구성



    // 각 셀의 내용을 구성하는 함수
    // 매우 중요

    func tableView(_ tableView: UITableView,
                   cellForRowAt indexPath: IndexPath)
    -> UITableViewCell {



        // dequeueReusableCell
        // 재사용 가능한 셀 가져오기

        // 메모리 절약 목적
        // 화면 밖 셀을 재활용함

        let cell =
        tableView.dequeueReusableCell(
            withIdentifier: "myCell",
            for: indexPath
        ) as! MyTableViewCell



        // MARK: guard let



        // Optional 안전 해제

        // movieData? :
        // Optional chaining

        // nil이면 실행 중단

        guard let mRank =
                movieData?
                .boxOfficeResult
                .dailyBoxOfficeList[indexPath.row]
                .rank
        else {

            return UITableViewCell()
        }



        guard let mName =
                movieData?
                .boxOfficeResult
                .dailyBoxOfficeList[indexPath.row]
                .movieNm
        else {

            return UITableViewCell()
        }



        // 문자열 보간법
        // \(변수)

        cell.movieName.text =
        "[\(mRank)위] \(mName)"



        // MARK: 일일 관객수 처리



        // if let
        // Optional 값 존재 시 실행

        if let aCnt =
            movieData?
            .boxOfficeResult
            .dailyBoxOfficeList[indexPath.row]
            .audiCnt {



            // NumberFormatter
            // 숫자 형식 변경 객체

            let numF = NumberFormatter()



            // decimal
            // 3자리 콤마 적용

            numF.numberStyle = .decimal

            // Int 변환
            // String -> Int

            let aCount = Int(aCnt)!

            // string(for:)
            // 숫자를 문자열로 변환

            let result =
            numF.string(for: aCount)!
            + "명"

            cell.audiCount.text =
            "어제 : \(result)"
        }

        // MARK: 누적 관객수 처리

        if let aAcc =
            movieData?
            .boxOfficeResult
            .dailyBoxOfficeList[indexPath.row]
            .audiAcc {

            let numF = NumberFormatter()

            numF.numberStyle = .decimal

            let aAcc1 = Int(aAcc)!

            let result =
            numF.string(for: aAcc1)!
            + "명"

            cell.audiAccumulate.text =
            "누적 : \(result)"
        }

        // 셀 반환
        return cell
    }

    // MARK: 헤더 제목



    // 테이블 상단 제목
    func tableView(_ tableView: UITableView,
                   titleForHeaderInSection section: Int)
    -> String? {

        return "🍿박스오피스(영화진흥위원회제공:"
        + makeYesterdayString()
        + ")🍿"
    }

    // MARK: 푸터 제목

    // 테이블 하단 제목
    func tableView(_ tableView: UITableView,
                   titleForFooterInSection section: Int)
    -> String? {

        return "made by CJH"
    }

    // MARK: IBOutlet

    // storyboard의 tableView 연결

    // IBOutlet
    // Interface Builder Outlet

    // 스토리보드 객체와 코드 연결

    @IBOutlet weak var table: UITableView!


    // Optional 변수
    // 데이터 없을 수도 있음

    var movieData : MovieData?

    // MARK: API 주소

    // 영화진흥위원회 API URL

    // targetDt=
    // 날짜를 뒤에 붙일 예정

    var movieURL =
    "https://kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList.json?key=b735d5397e2b621db6dda1700ae5beef&targetDt="

    // MARK: viewDidLoad

    // 화면 로딩 후 1번 실행

    override func viewDidLoad() {

        super.viewDidLoad()

        // delegate 연결
        table.delegate = self

        // datasource 연결
        table.dataSource = self

        // URL 뒤에 날짜 추가
        movieURL += makeYesterdayString()



        // API 호출
        getData()
    }





    // MARK: 날짜 함수



    // 전날 날짜 생성 함수
    func makeYesterdayString() -> String {



        // Calendar.current
        // 현재 기기 달력 사용

        // 하루(-1) 감소

        let y =
        Calendar.current.date(
            byAdding: .day,
            value: -1,
            to: Date()
        )!

        // 날짜 형식 객체

        let dateF = DateFormatter()

        // yyyyMMdd 형식 지정

        dateF.dateFormat = "yyyyMMdd"

        // Date -> String 변환

        let day =
        dateF.string(from: y)

        return day
    }


    // MARK: API 통신

    func getData(){

        // 문자열 -> URL 변환

        guard let url =
                URL(string: movieURL)
        else { return }

        // URLSession
        // 네트워크 통신 객체

        let session =
        URLSession(configuration: .default)
        
        // dataTask
        // 비동기 네트워크 작업

        let task =
        session.dataTask(with: url) {

            data, response, error in

            // 에러 발생 시 종료

            if error != nil {

                return
            }

            // 데이터 없으면 종료

            guard let JSONdata = data
            else {

                return
            }



            // 디버깅용 출력

            print(JSONdata)



            // JSONDecoder 생성

            let decoder = JSONDecoder()

            do {

                // JSON -> 구조체 변환

                let decodedData =
                try decoder.decode(
                    MovieData.self,
                    from: JSONdata
                )

                // 첫 번째 영화 출력

                print(
                    decodedData
                        .boxOfficeResult
                        .dailyBoxOfficeList[0]
                        .movieNm
                )
                // 데이터 저장
                self.movieData = decodedData
                // UI 작업은 Main Thread에서 수행
                DispatchQueue.main.async {

                    // 테이블 새로고침
                    self.table.reloadData()
                }
            } catch {

                // JSON 파싱 실패

                print(error)
            }
        }
        // task 실행
        // resume 안 하면 실행 안 됨

        task.resume()
    }
}
//
//  ViewController.swift
//  MovieCjh
//

import UIKit

// MARK: - JSON 데이터 구조

// Codable
// JSON 데이터를 Swift 구조체로 자동 변환 가능

struct MovieData: Codable {
    let boxOfficeResult: BoxOfficeResult
}

struct BoxOfficeResult: Codable {
    let dailyBoxOfficeList: [DailyBoxOffice]
}

struct DailyBoxOffice: Codable {
    let movieNm: String      // 영화 제목
    let audiCnt: String      // 일일 관객수
    let audiAcc: String      // 누적 관객수
    let rank: String         // 순위
}



// MARK: - ViewController

class ViewController: UIViewController {



    // MARK: IBOutlet

    @IBOutlet weak var table: UITableView!



    // MARK: 변수

    // API에서 받아온 영화 데이터 저장
    var movieData: MovieData?



    // 영화진흥위원회 API 주소
    let baseURL =
    "https://kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList.json?key=b735d5397e2b621db6dda1700ae5beef&targetDt="



    // MARK: viewDidLoad

    override func viewDidLoad() {
        super.viewDidLoad()

        setupTableView()

        getData()
    }



    // MARK: 테이블 설정

    func setupTableView() {

        // delegate 연결
        table.delegate = self

        // datasource 연결
        table.dataSource = self
    }



    // MARK: 전날 날짜 생성

    func makeYesterdayString() -> String {

        // 현재 날짜에서 하루 감소
        let yesterday =
        Calendar.current.date(
            byAdding: .day,
            value: -1,
            to: Date()
        )!

        // 날짜 형식 설정
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyyMMdd"

        // Date -> String 변환
        return formatter.string(from: yesterday)
    }



    // MARK: 최종 URL 생성

    func makeMovieURL() -> String {

        return baseURL + makeYesterdayString()
    }



    // MARK: API 데이터 요청

    func getData() {

        // 문자열 -> URL 변환

'computing' 카테고리의 다른 글

20260526_iOS12  (0) 2026.05.26
20260525_R11  (0) 2026.05.20
20260512_iOS10  (0) 2026.05.12
20260511_R9  (0) 2026.05.11
20260504_빅데이터08  (0) 2026.05.04