[TIL]05.19

rbw·2022년 5월 19일
0

TIL

목록 보기
22/97
post-thumbnail

Pull Request

Mac 환경에서 Pull Request(PR)을 하는 방법에 대해서 알아보겠습니다.

1. 터미널 설정

먼저 원격 저장소를 들고 올 폴더로 이동을 해야합니다.

// Terminal

cd 폴더주소

여기서 Mac에서 간단히 폴더 주소를 가져올 수 있는데 터미널에서 cd 를 입력 후에 원하는 폴더를 드래그하여서 터미널에 넣으면 간단히 해당 폴더로 이동할 수 있습니다.

2. clone, remote 설정

이제 로컬 저장소에 원격 저장소를 추가하는 작업을 진행 하면 됩니다.

git clone repository주소

위와 같이 작성을 해주면 깃허브 아이디와 토큰을 입력하라고 뜨는데 맞게 입력해주면 됩니다. 만약 토큰을 설정을 해야 한다면, 이 링크 로 들어가면 됩니다.

입력을 끝냈다면 다음 명령어로 잘 연결이 되어있는지 확인합니다.

git remote -v 

다음과 같이 뜬다면 원격저장소가 제대로 연결이 된 것입니다.

3. Branch 생성

이제 Pull Request를 하기 위해 새로운 브랜치를 생성해야 합니다.

git switch -c newbranch

위의 명령어로 브랜치를 만들고 바로 현재 브랜치로 바꿀 수 있습니다.

4. add commit push

이제 해당 브랜치에서 작업을 끝냈다면 add 를 사용하여서 변경사항을 저장하고 commit으로 커밋 메시지를 남긴다음 push 하면 됩니다. 이 때, 해당 브랜치에서 push 해야한다는 것의 주의해야 합니다.

// 변경사항 전부를 add
git add . 

git commit -m "first commit"

git push origin newbranch

Pull Request 생성

이제 push를 하였기 때문에, 깃허브에 들어가보면 새로운 버튼이 활성화가 되어 있습니다.

Compare & pull request 버튼을 눌러 주고, 내용을 작성이 가능합니다.

Merge

레포지토리 담당자가 자신일 경우에는 충돌 되는 코드가 없는지 확인하고, merge 하면 됩니다. 만약 자신이 관리하는 경우가 아닐 경우에(팀 프로젝트, 회사 등) PR을 받은 담당자가 코드 내역을 확인하고 merge 여부를 확인하여서 병합합니다.

Branch 삭제, Pull

이제 원격저장소에 올렸으므로, 작업 브랜치는 삭제를 하고, 로컬 저장소에서는 동기화를 시켜 줍니다.

git branch -D newbranch

git pull remote-name

pull 을 사용하지 않고 push를 하려고 하면, 에러가 나는 경우가 있으니 올리기 전에 pull 을 하는 편이 좋습니다.

git pull origin master = git pull [원격저장소 이름][원격 저잦오세엇 받아오고자 하는 브랜치 이름] 이라는 의미이다. git pull 만 입력하면 해당 저장소에 내용을 현재 브랜치에 들고온다고 생각하면 된다.

여기까지 PR을 하는 방법에 대해서 알아보았습니다. 이번에 살펴 본 부분은, Fork 를 사용하지 않았는데 이 부분은 단순히 다른 사람의 저장소를 자기 깃허브에 복사한다는 차이가 있다는 것 외에는 위의 과정이랑 전부 동일하므로 쉽게 할 수 있을거라 생각합니다.


SwiftUI의 레이아웃 시스템

이번에는 SwiftUI가 어떤 방식으로 레이아웃을 그리는지에 대해서 알아보겠습니다.

Layout Algorithm

만약 파란색 배경의 원 안에 텍스트가 존재하는 뷰를 만든다고 할 때, 이를 코드로 구현을 해본다면,

Text("Reset")
    .background(
        Circle()
        .fill(Color.blue)
    )

위 코드로는 다음 사진과 같은 화면으로 나올 것입니다

이렇게 나오게 되는 이유는 SwiftUI의 레이아웃 알고리즘에 대해 알고 있어야 합니다. SwiftUI의 모든 레이아웃은 다음 4가지 단계를 통해 그려집니다.

  1. 컨테이너 뷰(바로 위의 상위 뷰)가 사이즈를 제안합니다.
  2. 하위 뷰가 자신의 사이즈를 결정합니다.(하위 뷰는 상위 뷰가 제안한 사이즈를 그대로 사용하거나, 본인이 자신의 사이즈를 결정하기도 합니다)
  3. 하위 뷰가 컨테이너 뷰에 자신의 사이즈를 알립니다. (2단계에서 결정된 사이즈로 컨테이너 뷰의 사이즈가 정해집니다.)
  4. 컨테이너 뷰가 하위 뷰를 가운데 정렬 시킵니다.

이 절차와 뷰 디버깅을 통해 그려진 뷰의 계층을 보면서, 위의 코드를 분석해보겠습니다.

  1. 루트 뷰가 화면 전체 사이즈를 background 에게 제안합니다. 그리고 background 는 다시 Text에게 전달합니다. (Modifier는 새로운 뷰를 만들고 이전 뷰를 감싸서 반환한다는 것을 기억한다면, backgroundText를 감싸고 있다는 것을 이해 할 수 있습니다.)

  2. 하지만, Text는 자신이 담고 있는 내용만큼만 필요하기 떄문에 콘텐츠의 내용 만큼만 사용할 것을 background에게 알립니다.

  3. 다시 background는 이를 하위 뷰인 ShapeView에 알리고 ShapeView 는 이를 Circle에게 알립니다.(ShapeViewText는 형제-자매 관계 입니다.) Circle은 받은 크기를 그대로 사용하여 해당 크기에 딱 맞는 원을 그립니다.

  4. 그리고 이를 background 에 전달하고 background는 다시 이 크기를 루트 뷰에 전달하고 루트 뷰는 해당 뷰를 가운데 정렬 합니다.

이제 우리가 원하는 레이아웃을 그리기 위해서는 어떤 방식이 있을지 알아보겠습니다.

GeometryReader

UIKit에서는 크기를 사용할 때 객체에 직접 접근을 하여 값을 가져올 수 있었지만, SwiftUI에서는 불가능하므로, 이 문제를 GeometryReader로 해결하려고 합니다.

이는 컨테이너 뷰의 한 종류로, 자신의 바로 위에 있는 상위 뷰의 기하학 정보를 자신이 포함하는 자식 뷰에게 제공하는 역할을 합니다.

사용 예시는 다음과 같습니다.

Text("hi~~")
    .padding()
    .fixedSize() // Text에만 존재하는 수정자로, 아무리 문자열이 길어도 한줄에 보여줍니다.
    .background(
        // 이때, proxy의 너비는 Text의 너비와 같습니다.
        GeometryReader { proxy in
            self.width = proxy.size.width // error
            // 생성자로 ViewBuilder를 받기 때문에, 해당 할당식은 작성이 불가능
        }
    )
        .frame(width: self.width, height: self.width)
        .background(
            Circle()
            .fill(Color.blue)
        )
    

이 시점에서 proxy 의 정보를 width에 할당을 하려면 이 정보를 뷰 계층 위로 전달을 해야합니다. 이럴 때 사용하는것이 Preference 입니다.

Preference

이는 키-값 메커니즘으로 하위 뷰 정보를 상위 뷰에 전달할 수 있는 수단입니다. 이를 위해선 먼저 Preferencekey 프로토콜을 따르는 키를 정의해야합니다.

struct SizeKey: PreferenceKey {
  static func reduce(value: inout CGFloat?, nextValue: () -> CGFloat?) {
    value = nextValue()
  }
}

간단하게 설명하자면, reduce 메소드는 SizeKey를 사용하는 하위 뷰들을 순회하면서 상위 뷰가 접근할 수 있는 값을 만들기 위해 이들의 값을 취합하는 역할을 합니다.

struct ContentView: View {
  @State private var width: CGFloat? = nil

  var body: some View {
    Text("Reset")
    .padding()
    .fixedSize()
    .background(
      GeometryReader { proxy in
				Color.clear.preference(key: SizeKey.self, value: proxy.size.width)
			}
    )
    .frame(width: self.width, height: self.width)
    .background(
      Circle()
      .fill(Color.blue)
    )
    .onPreferenceChange(SizeKey.self) { value in
			self.width = value
		}
  }
}

위와 같이 간단하게 트릭을 사용하여서 proxy 정보를 전달 할 수 있습니다.

  1. ColorView 프로토콜을 따릅니다. 때문에, 사용자는 볼 수 없는 Color.clearpreference를 통해 proxy.size.width를 전달하고 있습니다.

  2. 상위 뷰(Text)에선 하위 뷰에서 전달한 정보를 onPreferenceChange를 통해서 받을 수 있습니다.

이런식으로, 원하던 레이아웃을 구현할 수 있습니다.


참조

https://zeddios.tistory.com/27

https://keepdev.tistory.com/19

https://protocorn93.github.io/tags/PreferenceKey/

profile
hi there 👋

0개의 댓글