m1 맥북 초기 설정 정리해보기

|

m1 맥북 구매 후 초기 설정해야할 내용을 정리해보았습니다.
필요한 내용은 계속해서 추가해 나갈 예정이며 더 좋은 방법이 있거나 잘못된 부분이 있다면 알려주세요! :)


Homebrew 설치하기

m1 맥북 용 homebrew 설치 명령어

/bin/bash -c "$(curl -fsSL https://gist.githubusercontent.com/nrubin29/bea5aa83e8dfa91370fe83b62dad6dfa/raw/48f48f7fef21abb308e129a80b3214c2538fc611/homebrew_m1.sh)"

아래는 기존 homebrew 설치 명령어

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

만약 기존과 같이 위 코드로 homebrew를 설치하고 brew help와 같은 명령어를 터미널에 입력해보면 아래와 같은 문구가 나타날 것이다.

zsh: command not found: brew

터미널 커맨드 창에서 brew라는 명령어를 찾을 수 없다는 의미로 이럴때는 아래 명령어를 터미널에 입력!

eval $(/opt/homebrew/bin/brew shellenv)

그러면 brew help와 같은 명령어를 입력했을 때 아래와 같은 창이 나옴

brew cask

  • brew ~ : 커맨드 라인 프로그램 (c, java, python 같은..)
  • brew cask ~ : GUI 프로그램 (Safari, Chrome, Word 같은..)
  1. brew update : 홈브류 최신버전으로 업데이트
  2. brew upgrade [프로그램명]: 홈브류에 설치된 프로그램 최선버전으로 업데이트
  3. brew search [프로그램명] : 홈브류를 통해 설치 가능한 프로그램 찾기

예전에는 brew cask 이런식으로 명령어를 사용해서 앱을 깔았는데, 이제는 이렇게 안해도 되는것 같다. (그래서 나는 그냥 진행했다….ㅎ) 사용하려면 brew install --cask 사용!

brew cask 는 2.7.0 업데이트부터 명령이 비활성화 되었다. 2020-12-01 부터 사용 불가.

Git 설치

최신버전의 git으로 설치하는 명령어

brew install -s git

git이 제대로 깔려있는 지 확인하고 싶다면 터미널에 git이라고 쳐본다.
아래와 같은 화면이 보인다면 잘 깔려있는 것

Mac SSH 생성 및 Github 등록

맥북에 SSH 키가 있는지 확인

cat ~/.ssh/id_rsa.pub

키가 있다면 해당 키가 터미널 창에 보일 것이다. 없다면 아래와 같은 메시지가 뜬다.

No suck file or directory

그러면 이제 생성해보자.

ssh-keygen

위 명령어를 입력하면 터미널에서 경로와 파일명을 설정하라는 메시지가 뜰것이고 나는 그냥 여기서 추천해준(지정해준) 대로 enter 누르며 진행헀다. 잘 생성되어있는지 다시 확인해보자.

cat id_rsa.pub

그러면 터미널창에서 내 SSH 키가 보일 것이고 이를 복사해놓은 상태로 Github으로 고고

  1. Github 홈페이지에 들어간다
  2. 오른쪽 상단 내 계정을 눌러 settings > SSH and GPG keys 탭 선택
  3. New SSH key 클릭
  4. 타이틀은 아무거나 상관없지만, 보통 사용하는 기기 이름을 적어줍니다.
  5. 복사한 id_rsa.pub을 붙여넣기!
  6. 저장

git config

터미널에서 git configuration을 진행합니다.

git config --global user.name "지정할 이름"
git config --global user.email "지정할 이메일"

iterm2 설치

brew install iterm2

사실 개발환경에서는 에러 메시지가 영어로 나오는것이 훨씬 좋기때문에(검색에 용이…) 맥북 언어 설정 자체를 영어를 우선으로 두는게 좋다. 그럼에도 만약 한글을 사용하게 되어 혹시나 한글이 깨진다면 ⌘ + , -> profile -> text -> unicode -> form을 NFC로 변경을 하면 된다고 한다.

zsh, oh-my-zsh

// zsh 설치
brew install zsh

// oh-my-zsh 설치
sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"

zsh 관련 설치

// zsh-autosuggestions > 터미널 입력 시 history 기반 단어를 추천
brew install zsh-autosuggestions

설치 진행 후 ~/.zshrc에 아래 명령어를 추가

source /opt/homebrew/share/zsh-autosuggestions/zsh-autosuggestions.zsh
// zsh-syntax-highlighting
git clone https://github.com/zsh-users/zsh-syntax-highlighting.git "$HOME/.zsh/zsh-syntax-highlighting"

설치 진행 후 ~/.zshrc에 아래 명령어를 추가

echo "\nsource $HOME/.zsh/zsh-syntax-highlighting/zsh-syntax- highlighting.zsh" >> "$HOME/.zshrc"

이렇게 설치를 하고나면 터미널을 나갔다 다시 들어와도 되고 source ~/.zshrc를 하면 설치한 내용들이 적용되어있는 것을 볼 수 있을 것이다.

Node.js 설치

brew install node

이외 설치해볼 것들

  • brew instlal google-chrome
  • brew install vlc
  • brew install atom
  • brew install slack

맥 시간 설정 안되어있을 경우

환경설정 > 날짜 및 시간 > 좌물쇠 풀고 > 시간대 설정 변경해주기

iterm 테마 꾸미기

플러그인 설치도 할 수 있지만 나는 이런거엔 관심이 별로 없기에..

환경설정 들어가서 바꿔주기

iterm 상태바 보여주기

iterm configuration 에 들어가서
profile > session > Status bar enabled 체크 > Configure Status Bar 선택해 원하는 항목 추가 저장하고 나와서 Appearance > Status bar location으로 상태바 위치 설정

맥북 대략적인 초기 기본 설정

  • mission control > Automatically rearrange Spaces based on most recent use > 체크 안함: 최근에 만진 화면 순서대로 미션 컨트롤 창 순서가 바뀌지 않도록 설정
  • 언어는 무조건 영어가 우선순위 가 될 수 있도록 (선택사항이긴 함): locale 설정때문에 오류가 발생하는 걸 방지해주고 영어 오류 메시지가 구글 검색에 더 용이함
  • 패스워드, 분실대비 스크린 메시지 설정, 디스크 암호화 등
  • Keyboard > text > 자동변경 옵션, 입력한 단어 변경 등 위에서부터 3개 다 체크 해제
    • Correct spelling automatically 체크 해제
    • Capitalize words automatically 체크 해제
    • Add period with double-space 체크 해제
    • Use smart quotes and dashes 반드시 해제해주기!
  • Keyboard > shortcut > Use Keyboard navigation to move focus between controls: 키보드로 예/아니오 설정할 수 있는건데 이건 선택사항임
  • TrickPad > tap to click 선택!: 트릭패드 꾹 안누르고 터치만으로 클릭 가능하게 하는것
  • Accessibility > Pointer Control > Trackpad options > Enable dragging > three finger drag: 세 손가락으로 드래그 가능하게 함 > 요건 신세계였음
    • 근데 이 방법을 사용하면 원래 세 손가락으로 미션컨트롤 이동을 했는데, 이젠 네손가락으로 이동을 하게 됨(선택은 자유!)
  • finder preference > show all filename extensions 체크함: 모든 파일의 확장자를 보여줌

cocoapods 설치

  • 터미널복제 > 터미널2의 get info > use rosetta
  • 터미널2에서 sudo gem install ffi
  • iterm2로 돌아와서 brew install cocoapods

오토레이아웃을 더 공부하며 알게 된 점 정리해보기

|

개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.
공부하면서 더 추가해나갈 예정입니다. 틀린 부분 혹은 잘못된 부분이 있다면 알려주세요! :)


AutoLayout

view의 절대적인 좌표가 아닌 상대적인 좌표를 요할 때 사용한다.
오토레이아웃이 없으면 view의 크기는 고유 크기를 지니고 있다. (width, height)

multiplier

  • 연결하는 방식에 따라 비율이 달라진다.
  • 1>2, 2>1로 연결하냐에 따라 First Item, Second Item 이 정해지고 비율이 설정된다.

alignmebt + multiplier

  1. 부모뷰를 기준으로 이동
  2. 하나만 선택했을때 가로, 세로 정렬을 선택할 수 있음
    • Horizontally in Container, Vertically in Container 설정
  3. Align CenterX: 0.1 > 왼쪽으로 이동, 1.5 > 오른쪽으로 이동
  4. Align CenterY: 0.1 > 위로 이동, 1.5 > 아래로 이동

View를 겹치게 하기

2개 이상의 겹쳐진 뷰를 만들 때 단순히 자식뷰의 multiplier 값을 변경하는 것으로 한다면 부모 view가 어떤 모양을 가지거나 라운드 처리를 해야하는 등의 view라면
inspector에서 clip to bounds 속성을 체크하게 된다. 이러면 부모뷰에서 겹쳐지지 않은 영역은 잘리게 된다. > 동등하지 않은 레벨의 정렬

view를 겹쳐지게 하기 위해서 자식 뷰를 부모 뷰에서 꺼내고 두 뷰를 선택한 뒤 Top Edges와 Horizontal Centers를 체크한다. > 동등한 레벨의 정렬

그리고 겹쳐질 뷰의 Align Center Y의 Second Item을 Center Y 로 변경한다.

Priority

priority는 우선 Required(1000), High(750), Low(250)이 기본이며 원하는 만큼의 값을 직접 입력할 수 있다.
일단 기본으로 1000priority가 주어지는데 이것은 강한 우선순위로 다른 우선순위에 영향을 준다.

  • Hugging: 내 컨텐츠에 대한 본연의 사이즈 유지 우선순위
  • Compression Resistance: 배치한 방향에 대한 우선순위 (작지않게 버티겠다)
    • 우선순위가 크면 내 크기를 유지하고
    • 우선순위가 작으면 내 크기를 작게한다
    • 숫자가 높을수록 우선순위가 높고
    • 낮은 우선 순위는 늘어나게 된다.

Portrait(세로), Landscape(가로)

  • constraints는 세로모드일때와 같이 동일하게 지정
  • Vary for Traits 메뉴를 통해 width/height 변경에 따라 적용 가능한 디바이스 확인 가능
  • Vary for Traits에서 가로/세로 모드일때 적용하고 싶은 대로 뷰를 다시 정의함

stretching

  • x,y,w,h에 대한 설정 가능
  • 값이 0일때는 시작점붜 늘어나게 하는 것(제약없이 이미지가 늘어남, 단순 이미지 확대용)
    • width를 0.5로 한 경우 시작점부터 50% 영역까지 늘어남
    • y를 0.5로 한 경우 50%영역 이상 늘어남

SnapKit에 대해 아는만큼 정리해보기

|

개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.
공부하면서 더 추가해나갈 예정입니다. 틀린 부분 혹은 잘못된 부분이 있다면 알려주세요! :)


SnapKit

SnapKit을 사용할 때는 해석 방향이 중요

make.top.equalTo(viewProgress.snp.bottom).offset(30)

순차적으로 해석 (만들다 > 상단을 > 똑같게 > viewProgress의 하단과 > offset은 30

offset? inset?

  • offset: element와의 간격에 사용
  • inset: superView와의 간격에 사용

Q. childView가 superView로부터 top, bottom, left, right 50 spacing 각각 주려면 어떻게?

1. offset: childView의 constraint = superView의 constraint + offset

self.box.make { (make) in 
  make.top.equalToSuperView().offset(50)
  make.left.equalToSuperView().offset(50)
  make.right.equalToSuperView().offset(-50)
  make.bottom.equalToSuperView().offset(-50)
}

2. inset

self.box.make { (make) in
  make.top.left.bottom.right.equalToSuperView().inset(50)
}

위 코드는 아래와 같게 사용할 수도 있다.

self.box.make { (make) in
  make.edges.equalTo(UIEdgeInsets(top: 50, left: 50, bottom: 50, right: 50))
}

그치만 각각의 spacing이 같다면 위 방법이 더 낫다.

left, right / leading, trailing

기본적으로 leading, trailing을 사용하는게 localized 때문인데, 이와 같이 설정하면 right-to-left 순서로 읽는 지역에서는 화면이 거꾸로(flip)되어서 표시된다고 한다. 반면 left, right를 사용하면 안그럼!

  • left, right는 모든 지역에서 같은 방향으로 나오지만 leading, trailing은 오른쪽에서 왼쪽으로 읽는 지역에서는 flip된 ui가 나오게 된다.
  • text를 보여줄때에는 leading, trailing을 사용하는게 나을 것 같으며 그림, 지도와 같이 이미지가 보이는 view를 보여줄 때에는 left, right를 쓰는게 나을 것 같다

전체적인 예시를 한번 보자!

class mainVC: UIViewController {

  // 원하는 객채를 이름붙여 만들어줌 
  let nameLbl = UILabel()
  let nameTextField = UITextField()
  let changeBtn = UIButton()

  // 이름만 만들어준 객체를 실제로 뷰에 띄움 
  override func viewDidLoad() {
    super.viewDidLoad()
    self.view.addSubView(self.nameLbl)
    self.view.addSubView(self.nameTextField)
    self.view.addSubView(self.changeBtn)

    // 아래부터 띄워놓은 객체들에게 각각의 위치를 부여해줌
    self.nameLbl.snp.makeConstraints {
      // self.nameLbl은 superView로부터 center에 위치함 
      $0.center.equalToSuperView()
    }

    self.nameTextField.snp.makeConstraints {
      // self.nameTextField의 top은 superView로 부터 80 떨어짐
      // leading, trailing은 각각 24만큼 떨어짐 
      $0.top.equalToSuperView().offset(80)
      $0.leading.equalToSuperView().offset(24)
      $0.trailing.equalToSuperView().offset(-24)
  }

    self.changeBtn.snp.makeConstraints {
      // changeBtn의 top은 nameLabl의 bottom으로부터 24 떨어짐
      // leading, trailing은 nameLbl과 같게
      $0.top.equalTo(self.nameLbl.snp.bottom).offset(24)
      $0.leading.trailing.equalTo(self.nameLbl)
    }
  }
}

translatesAutoresizingMaskIntoConstraints = false

코드로 constraints를 잡으려면 translatesAutoresizingMaskIntoConstraints = false를 명시해줘야하지만
snapKit은 translatesAutoresizingMaskIntoConstraints = false를 내부에서 알아서 해준다.

따라서 굳이 우리가 이를 명시해주지 않아도 되며, 아래는 snapKit의 LayoutConstraintItem 파일에 적혀있는 코드이다.

extension LayoutConstraintItem {
  internal func prepare() {
    if let view = self as? ConstraintView {
      view.translatesAutoresizingMaskIntoConstraints = false
    }
  }
}

Anchor

1. 모든 앵커와 제약 조건 자체를 함께 연결하는 것이 가능

child.snp.makeContraints { make in 
  make.leading.top.trailing.bottom.equealToSuperView()
}

2. edges를 이용해 더욱 간편하게 사용 가능

child.snp.makeConstraints { make in 
  make.edges.equalToSuperView()
}

3. view에 inset 값을 주고싶다면 inser() 가능

child.snp.makeConstraints { make in 
  make.edges.equealToSuperView().inset(15)
}

Constraints

  • multipliedBy()
make.width.equalToSuperView().multipliedBy(0.45)

superView와 width를 같게 만들면서 0.45를 곱한 상태

암시

constraints 기준이 되는 view 값을 최대한 짧게 작성한다.
아래 코드는 다 같은 의미를 지닌다.

view.snp.makeConstraints { make in 
  make.width.equalTo(otherView.snp.width
  make.centerX.equalTo(otherView.snp.centerX)
}

view.snp.makeConstraints { make in 
  make.width.equalTo(otherView)
  make.centerX.equalTo(otherView)
}

view.snp.makeConstraints { make in 
  make.width.centerX.equalTo(otherView)
}

UpdateConstraints

constraints 기준이 될 기존에 지정한 view가 바뀌는게 아닌 constant value(상수값)만 업데이트

extension QuizVC {
  override func willTransition (
    to newCollection: UITraitCollection,
    with coordinator: UIViewControllerTransitionCOordinator
  ) {
    super.willTransition(to: newCollection, with: coordinator)

    // 현재 방향을 설정(bool)
    let isPortrait = UIDevice.current.orientation.isPortrait

    // 세로일 경우 45, 가로일 경우 65로 높이를 바꿔줌
    lblTimer.snp.updateConstraints { make in 
        make.height.equalTo(isPortrait ? 45 : 65)
    }

    // 글꼴 크기를 변경해줌 
    lblTimer.font = UIFont.systerFont(ofize: isPortrait ? 20 : 32, weight: .light)
  }
} 

RemakeConstraints

constant value만 변경되는 것이 아닌 기준이 될 view도 업데이트
기존에 존재하던 constraints는 삭제된다.

func updateConstraints {
  pView.snp.remakeConstraints { make in 
    make.top.equalTo(view.safeAreaLayoutGuide)
    make.width.equalToSuperView().multipliedby(0.1)
    make.height.equalTo(32)
    make.leading.equalToSuperView()
  }
}

lessThanOrEqualTo, priority > 아직 공부 더 필요

override func updateConstaints() {
  self.prowingBtn.snp.updateConstraints { make in
    make.center.equalTo(self);
    make.width.height.equalTo(buttonSize).priority(250)
    make.width.height.lessThanOrEqualTo(self)
  }
  super.updateConstraints()
}

UIRefresh controller 사용해보기

|

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


UIRefresh Controller

리스트 형식의 테이블 뷰를 사용할때 새로고침 버튼을 두는것보다는 테이블 뷰를 아래로 당김으로써 새로고침을 진행하는 것이 좋다고 한다.
실제로 우리가 많은 앱을 사용하다 보면 앱의 최 상단을 위에서 아래로 잡아당겼을 경우 새로고침이 되는 경우가 많음을 쉽게 떠올릴 수 있을 것이다.

@available(iOS 6.0, *)
open class UIRefreshControl : UIControl {


    /* The designated initializer
     * This initializes a UIRefreshControl with a default height and width.
     * Once assigned to a UITableViewController, the frame of the control is managed automatically.
     * When a user has pulled-to-refresh, the UIRefreshControl fires its UIControlEventValueChanged event.
     *
    */
    public init()


    open var isRefreshing: Bool { get }


    open var tintColor: UIColor!

    open var attributedTitle: NSAttributedString?


    // May be used to indicate to the refreshControl that an external event has initiated the refresh action
    @available(iOS 6.0, *)
    open func beginRefreshing()

    // Must be explicitly called when the refreshing has completed
    @available(iOS 6.0, *)
    open func endRefreshing()
}

UIRefreshControl 내부를 살펴보면 iOS6.0 버전 이상부터 지원이 되고있으며 UIControl를 상속받고 있음을 볼 수 있다.
isRefreshing 은 현재 리프레쉬가 진행중인지를 나타나며 tintColor 를 통해 색의 변화도 줄 수 있다.
attributedTitle 를 통해 새로고침 indicator 아래에 다른 글귀를 줄 수도 있다

  • beginRefreshing: 새로고침이 시작됐음을 알려준다
  • endRefreshing: 새로고침이 끝났음을 알려준다

실제 구현해보기

테이블뷰가 구현되어있는 뷰 컨트롤러로 가봅시다.

class HomeVC: UIViewController {
    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        initUI()
        initRefresh()
    }

    func initUI() {
        self.tableView.delegate = self
        self.tableView.dataSource = self
    }

    func initRefresh() {
        let refresh = UIRefreshControl() // UIRefreshControl 인스턴스화
        refresh.addTarget(self, action: #selector(updateTableView(refresh:)), for: .valueChanged)  // target 설정
        if #available(iOS 10.0, *) {
            tableView.refreshControl = refresh
        } else {
            tableView.addSubview(refresh)
        }
    }

    @objc func updateTableView(refresh: UIRefreshControl) {
        refresh.endRefreshing()
        tableView.reloadData()
    }
}

구체적인 테이블 뷰에 들어가는 데이터는 생략하였습니다.

UIRefreshControl를 인스턴스화 하여 target 설정을 해주면 스와이프 액션이 취해졌을 때, 연결해놓은 updateTableView 함수를 호출합니다.
updateTableView함수가 호출되면 리프레쉬를 종료하는 endRefreshing 함수를 호출함으로써
initRefresh 함수는 종료하며 tableView는 reloadData를 하게 됩니다.

masksToBounds와 clipsToBounds 차이점?

|

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


예시 상황

어떤 네모난 textView 안에 “안녕하세요”라는 텍스트가 들어있다고 생각해보자.
이때 이 네모난 textView를 동그랗게 즉, radius를 줬다고 하자. 그러면 textView의 텍스트는 어떻게 될까?

아마도 네모난 부분에서 동그랗게 변해진 부분에 존재하는 텍스트는 동그래진 만큼 잘려서 보이지 않게 될 것이다.

때에 따라서는 이 텍스트가 잘리면 안되는 상황도 분명 존재할텐데!
그때 바로 사용하는 것이 clipsToBounds, masksToBounds이다.

우선 이 둘이 하는 기능 자체는 똑같은데, 불러오는 곳이 다르다.

textView.layer.masksToBounds
textView.clipsToBounds

즉, masksToBounds는 layer의 프로퍼티이고 clipsToBounds는 그냥 textView의 프로퍼티이다.
이때 알아두면 좋을 건 textView 뿐만 아니라, 버튼, 라벨에서도 불러올 수 있는 프로퍼티라는 것!

masksToBounds

open var masksToBounds: Bool

masksToBounds의 기본값은 false이다. 그렇다면 이때 true, false가 의미하는것은 무엇일까?

  • true: textView의 테두리가 기준으로, 위에 설명처럼 텍스트는 잘리게 된다.
    • textView라는 큰 뷰가 있고 그 안에 “안녕하세요”라는 텍스트가 있는것으로 큰 뷰를 기준으로 바깥에 있는것은 잘리게 된다.
  • false: textView 안의 내용 또한 잘리지 않고 “안녕하세요” 모두 보이게 된다.

clipsToBounds

open var clipsToBounds: Bool  // When Yes, content and subviews are clipped to the bounds of the view. Default is No

clipsToBounds 또한 masksToBounds와 같이 Bool 타입이다.
주석 내용또한 살펴보면 true일때 내용들과 서브뷰들은 뷰의 테두리를 기준으로 잘리게 되며 default는 false이다.

masksToBounds와 같이 false를 주지 않으면 안의 내용은 잘리게 된다.