Xcode Storyboard 삭제 및 Scene delegate 삭제하는 방법

|

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


회사에서는 모든 UI를 코드로 짜고있다. 스토리보드를 무척 사랑했던 나로서는 정말 슬픈일이었지만, 어쩌겠나요!
앞으로는 코드로 UI를 짜는것이 습관화 되어야 하기에 개인 실습 프로젝트를 하나 파게 되었고
그러면서 XCode에서 스토리보드와 Scene delegate를 샂게하는 방법을 같이 정리해보려고 합니다!

Storyboard 삭제하기

스토리보드를 제거하기 위해서는 프로젝트가 생성되는 Main.Storyboard와의 연동된 부분을 끊으면 된다.

Info.plist에서 Main Storyboard file base name > Main을 지운다.

혹은 프로젝트 설정에서 [Main Interface]에서 Main을 지우면 Info.plist에도 반영된다. 이 방법을 사용해도 같이 반영된다.

Main.Storyboard 파일을 삭제한다.

해당 파일은 더이상 사용하지 않기 때문에 삭제해도 괜찮다.

SceneDelegate 삭제하기

기존에 SceneDelegate에서 UIWindow를 설정하는 부분을 예전처럼 AppDelegate로 옮기고, Scene관련 파일과 설정을 제거한다.

AppDelegate 에서 Scene 관련 함수 정의부를 제거한다.

// MARK: UISceneSession Lifecycle

    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
        // Called when a new scene session is being created.
        // Use this method to select a configuration to create the new scene with.
        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
    }

    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
        // Called when the user discards a scene session.
        // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
        // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
    }

AppDelegate에 UIWindow 설정 로직을 추가한다.

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        window = UIWindow()
        window?.rootViewController = ViewController()
        window?.makeKeyAndVisible()

        return true
    }    
}

SceneDelegate 파일을 삭제한다.

해당 파일은 더이상 사용하지 않기에 삭제하도록 한다.

Info.plist에서 Application Scene Manifest 항목을 통쨰로 삭제한다.

확인해보기

ViewController의 기본뷰에 배경색을 입히고 앱을 실행시켜 적용한 배경색이 잘 뜨는지 확인해보자.

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.

        view.backgroundColor = .blue
    }
}

자주 사용하지만 헷갈리는 git 명령어 정리해보기

|

개인적인 연습 내용을 정리한 글입니다.
더 좋은 방법이 있거나, 잘못된 부분이 있으면 편하게 의견 주세요. :)


git branch 생성하기

git branch [만들 브랜치 이름]

git branch 확인하기

git branch -r  // 원격 저장소 브랜치 리스트 확인
git branch -a  // 원격, 로컬 모든 저장소의 브랜치 리스트 확인

git branch 가져오기

git checkout -t [가져올 브랜치 경로/이름]

git branch 이름 변경하기

git branch -m [기존 브랜치 이름] [바꾸고 싶은 브랜치 이름]

iOS DZNEmptyDateSet 라이브러리 사용해보기

|

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


DZNEmptyDataSet

테이블 뷰나 컬렉션 뷰 등에 데이터가 없을 때, 보여줄 수 있는 심플한 화면을 손쉽게 관리할 수 있는 라이브러리

사용이유

  1. 데이터가 없을때의 단순히 흰색 화면을 피학 화면이 비어있는 이유를 사용자에게 전달 가능
  2. 일관성 유지 및 사용자 경험 개선 제공
  3. 브랜드 존재감 제공

Features

  • UITableView, UICollectionView와 호환이 된다. 뿐만 아니라 UISearchDisplayController, UIScrollView와도 호환가능
  • 이미지, 제목 및 설명 레이블, 버튼을 표시함으로써 레이아웃 및 모양의 다양성을 제공
  • NSAttributedString 또한 사용가능
  • 오토레이아웃을 사용함으로써 회전과 함께 콘텐츠를 자동으로 뷰의 중앙에 배치시켜준다. > 수직, 수평 정렬을 허용
  • 배경색상 또한 사용자 정의 가능
  • 테이블뷰 탭 제스처 허용
  • 스토리보드와 호환 가능
  • iOS6, tcOS9 이상부터 호환가능, iPhone, iPad, Apple TV와 호환 가능

해당 라이브러리는 UITableView, UICollectionView 클래스를 확장할 필요 없는 방식으로 설계되어있다.
UITableViewController, UICollectionViewController를 사용할 때 여전히 작동이 가능하다.

DZNEmptyDataSetDelegate, DZNEmptyDataSetSource 만 준수한다면 애플리케이션의 내용과 빈 상태의 모양을 완전히 사용자 지정 가능하다.

사용해보기

pod 'DZNEmptyDateSet'

viewcontroller

class ViewController: UIViewController {
  func viewDidLoad() {
    self.viewDidLoad()

    self.tableView.emptyDataSetSource = self
    self.tableView.emptyDataSetDelegate = self
  }
}

// MARK: DZNEmptyDataSetDelegate
extension ViewController: DZNEmptyDataSetDelegate {
    // 스크롤 권한 요청 > default는 false
    func emptyDataSetShouldAllowScroll(_ scrollView: UIScrollView!) -> Bool {
        return true/false
    }
}

// MARK: DZNEmptyDataSetSource
extension ViewController: DZNEmptyDataSetSource {
    // 비어있는 상태의 이미지 설정
    func image(forEmptyDataSet scrollView: UIScrollView!) -> UIImage! {
        return
    }
    // 비어있는 상태의 제목 설정
    func title(forEmptyDataSet scrollView: UIScrollView!) -> NSAttributedString! {
        return
    }
}

iOS tableView delegate와 collectionView delegate(필요한 내용 추가합니다)

|

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


tableView

setHighlighted

셀의 강조 표시된 상태를 설정하고 선택적으로 상태 간 전환 애니메이션을 실행

func setHighlighted(_ highlighted: Bool, animated: Bool)
  • highlighted: 셀을 강조 표시로 설정하려면 true, 아니면 false > default: false

쉽게말하면 셀을 터치했을때 화면의 섹이 살짝 바뀌는것을 볼수있다.
사용자가 셀을 선택했는지 안했는지를 확인해볼 수 있음. > 사용자 관점에서 좀더 편리하다는 장점이 있다.
개발자적 관점에서는 무엇을 터치했을때 에러가 발생했는지 조금더 직관적으로 볼 수 있다는 장점이 있을 듯 하다….

heightForHeaderInSection

특정 섹션의 헤더뷰 높이 지정

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int)

heightForFooterInSection

특정 섹션의 푸터뷰 높이 지정

func tableView(_ tableView: UITableView, heightForFooterInSection section: Int)

위 두개를 보통 사용하는건 이러한 예시가 있다.

테이블뷰의 타입을 그룹으로 했을때 기본적으로 섹션의 자동 높이가 설정되어 뷰에 나타나게 된다.
그러나 나는 그 섹션의 높이가 마음에 안들거나 조절을 해야하는 경우가 있을텐데, 그때 이 delegate를 사용해준다.

viewForHeaderInSection

특정 섹션의 헤더뷰 요청

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int)

viewForFooterInSection

특정 섹션의 푸터뷰 요청

func tableView(_ tableView: UITableView, viewForFooterInSection section: Int)

collectionView

scrollToItem

지정된 항목이 표시될 때까지 collectionView 스크롤

func scrollToItem(at indexPath: IndexPath, at scrollPosition: UICollectionView.ScrollPosition, animated: Bool)
  • indexPath: 스크롤할 뷰 항목의 인덱스 경로
  • scrollPosition: 스크롤 완료될 때 항목이 배치되어야 하는 위치
  • animated: 스크롤 동작 적용하려면 true, 스크롤 뷰의 내용을 즉지 조정하려면 false

예제 블로그를 통해 확인해보면
스크롤뷰가 스크롤 되는 동안 계속 호출되는 delegate라고 한다.

scrollViewWillEndDragging

스크롤 뷰의 드래그가 끝나기 직전에 델리게이트에 알림

optional func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>)

간단한 예시로 생각해보자.

테이블 뷰 안에 컬렉션 뷰가 있다고 생각해보자.
테이블 뷰 중간에 컬렉션 뷰가 있었고, 컬렉션 뷰의 셀을 스크롤 해놓은 상태에서 > index가 0이 아닌상태에서
테이블뷰를 아래로 스크롤했다고 생각해보자.

이때 다시 해당 컬렉션뷰로 돌아갔을때, 컬렉션 뷰의 컨텐트 인덱스는 과연 어디에 위치해 있을까?

이를 정해주는 delegate이다.

말 그대로 사용자가 스크롤을 하고 스크린과 손이 떨어졌을때 호출되는 메소드이다.
이를 통해 스크롤할 때 컨텐트의 위치를 조정하여 페이징되는 효과를 낼 수 있다.

예제 블로그 < 요 블로그 예제를 보면 이해가 쉬울 것 같다.

showsHorizontalScrollIndicator

가로 스크롤 바 표시 여부를 제어하는 부울 값

var showsHorizontalScrollIndicator: Bool { get set }

isPagingEnabled

페이징을 사용할 수 있는 여부를 결정하는 부울 값

var isPagingEnabled: Bool { get set }

iOS Dispatch Group 사용해보기

|

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


Dispatch Queue

dispatchQueue 라는 객체는 메인 스레드나 백그라운드 스레드에서 업무를 직렬이나 병렬적으로 수행하도록 한다.

큐에 업무를 보낼때, 백그라운드 큐에 넣으면 시스템이 알아서 수행해준다. 그런데 각 테스크가 어떤 스레드에 의해 수행되는지는 알수가 없다. 직접 구현해야하는 부분은 동기/비동기적으로 테스크가 수행할 수 있도록 하는 것. 이때 중요한 점은 메인스레드에서는 데드락 이슈로 인해 동기적인 처리를 하지는 않아야 한다.

  • 동기: 하나의 테스크가 끝나야 그 다음 테스크 진행
  • 비동기: 여러 테스크가 동시에 진행

이때 중요한 것은 스레드를 생성할 수 있는 갯수의 한계는 존재하기 때문에, dispatchQueue는 너무 많이 만들면 안된다.

  • 직렬: 하나씩 차례대로 테스크 전달
  • 병렬: 한번에 여러개의 테스크 전달

Dispatch Group

서로 다른 테스크들을 그룹화하여 테스크들이 완료될때까지 기다리거나 완료되면 알림을 받을 수 있도록 하는 것
여러작업을 하나로 묶는 것. 따라서 그룹에 포함된 모든 작업이 완료되어야 그룹이 완료된다.

사용 방법

  1. 테스크를 위해 concurrent queue를 생성
  2. 각각의 테스크를 묶을 수 있는 DispatchGroup를 생성
  3. 각각의 테스크들을 queue에 담을 때 .enter() 호출
  4. 각 테스크의 완료 시점에 .leave()를 호출
  5. .notify를 통해 완료 이벤트의 알림을 받고 각각의 테스크가 다 끝난 후 필요한 작업을 진행
let myQueue = dispatchQueue(label: "com.nil.work", attribute: .concurrent)

let myGroup = DispatchGroup()

myGroup.enter()
myQueue.async {
  for i in 1...10 {
    print("\(i), 가")
  }
  myGroup.leave()
}

myGroup.enter()
myQueue.async {
  for i in 100...105 {
    print("\(i), aaaa")
  }
  myGroup.leave()
}

myGroup.notify(queue: myQueue) {
  print("end...")
}
  • .enter()는 myGroup에 테스크를 포함시키는 것을 의미
  • .leave()는 DispatchGroup에 해당 테스크가 완료되었다고 알려주는 의미

enter와 leave는 서로 쌍을 이루어야 한다!!