Xcode 템플릿
왜 사용하게 되었는지
MARK 주석 기능을 활용해서 코드를 자주 분리했는데,
이를 팀 코드 컨벤션으로 사용하고자 하였습니다.
하지만 같은 내용의 주석을 반복해서 타이핑하는 나 자신을 보니 자괴감이 들어 무슨 방법이 없을까 고민했죠
검색을 해보니 Xcode 템플릿을 만들어서 사용하면 이를 해결할 수 있더군요!
구성요소
•
하나의 템플릿은 하나의 폴더로 묶입니다
Xcode 템플릿 파일의 구성요소는 위와 같이 4개입니다.
1.
___FILEBASENAME___.swift : 템플릿 자체 파일
2.
Template 아이콘 파일
3.
TemplateInfo.plit : 템플릿의 정보에 관한 파일
•
___FILEBASENAME___ 라는 문구는 템플릿을 사용해 파일을 만들 떄, 사용자가 입력한 파일의 이름으로 대치되는 Place Holder 라고 생각하시면됩니다.
만드는법
1. 템플릿 파일 작성
//___FILEHEADER___
import UIKit
class ___FILEBASENAMEASIDENTIFIER___: BaseViewController {
//MARK: - Properties
//MARK: - LifeCycle
override func viewDidLoad() {
super.viewDidLoad()
configureUI()
}
//MARK: - Selectors
//MARK: - Helpers
func configureUI() {
//레이아웃 구성
}
}
//MARK: - Preview
import SwiftUI
struct ___FILEBASENAMEASIDENTIFIER___Representable: UIViewControllerRepresentable {
typealias UIViewControllerType = ___FILEBASENAMEASIDENTIFIER___
func makeUIViewController(context: Context) -> ___FILEBASENAMEASIDENTIFIER___ {
return ___FILEBASENAMEASIDENTIFIER___()
}
func updateUIViewController(_ uiViewController: ___FILEBASENAMEASIDENTIFIER___, context: Context) {}
}
@available(iOS 13.0.0, *)
struct ___FILEBASENAMEASIDENTIFIER___Preview: PreviewProvider {
static var previews: some View {
___FILEBASENAMEASIDENTIFIER___Representable()
}
}
Swift
복사
•
___FILEBASENAMEASIDENTIFIER___ : 템플릿을 사용해 파일을 만들 때, 파일의 이름으로 대치되는 PlaceHoler
•
//___FILEHEADER___ : 파일의 헤더가 자동으로 위치하게 되는 PlaceHolder 입니다. 건드릴 필요 없죠
템플릿 작성 팁
•
팀 내부적으로 필수적으로 상속받아야 하는 클래스가 있다면 이를 템플릿에 작성시, 실수로 상속하지 않는 실수를 피할 수 있습니다.
예 : BaseViewController
•
팀 내부의 코드를 정리하는 컨벤션을 정해 이를 MARK 주석으로 작성하면 팀원들의 코드를 읽기 편해집니다.
1.
프로퍼티
2.
라이프사이클 이벤트
3.
셀렉터
4.
헬퍼 함수
5.
프리뷰 관련 코드
를 분리하는 용도로 사용하였습니다.
코드를 찾기 쉬워집니다.
•
UIKit 에서 PreView 를 보기위한 코드를 따로 추가할 필요없이 템플릿화해서 사용할 수도 있습니다.
•
필수적으로 구현하고자하는 헬퍼함수를 미리작성해두는 것도 좋습니다.
예 : configureUI() → UI 의 레이아웃을 구성하는 코드를 분리하는 용도.
사용법
위와 같이 열심히 만든 템플릿을
위 파일을 압축해제하여 아래 경로에 추가해준다.
터미널에서 아래 명령어를 실행하면 간편하다.
cd /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Templates/iOS/Source
open .
Bash
복사
위와 같이 템플릿을 추가해준다.
Xcode 를 껐다 켠다.
귀여운 Luke 템플릿이 추가되어 있는 걸 볼 수 있다.
이름을 바꾸어 파일 생성
잘 적용된 모습
컨벤션에 맞는 코드 예시
class LukeViewController: UIViewController {
//MARK: - Properties 데이터, UI와 같은 프로퍼티 UI 객체만의 특성을 초기화해줄 때, 클로져형태로 초기화해주게 됩니다.
private let data: Data = Data()
let label: UILabel = {
let label = UILabel()
label.text = "Hello World!"
return label
}()
let imageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleToFill
imageView.image = UIImage(systemName: "person.fill")
return imageView
}()
//lazy를 써야 addtarget 이 제대로 작동합니다.
private lazy var actionButton: UIButton = {
let button = UIButton(type: .system)
button.setTitle("Tweet", for: .normal)
button.titleLabel?.textAlignment = .center
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
button.setTitleColor(.white, for: .normal)
button.frame = CGRect(x: 0, y: 0, width: 100, height: 40)
button.layer.cornerRadius = 32 / 2
button.backgroundColor = .link
//action 에 대한 target 을 버튼으로 지정합니다.
button.addTarget(self, action: #selector(didActionButtonTap), for: .touchUpInside)
return button
}()
//MARK: - LifeCycle : View 의 라이프사이클 이벤트를 핸들링 하는 부분입니다.
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
configureUI()
}
//MARK: - Selectors : 타겟에 대한 액션을 정의하는 부분입니다. ( 없다면 생략 가능 )
@objc func didActionButtonTap() {
//버튼에 대한 action 이 들어가게 됩니다.
uploadData()
}
//MARK: - Helpers 헬퍼함수를 정의하는 부분입니다.
func configureUI() {
//MARK: 레이아웃을 짜는 로직이 들어가게 됩니다.
let safeArea = view.safeAreaLayoutGuide
view.addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
label.centerXAnchor.constraint(equalTo: safeArea.centerXAnchor).isActive = true
label.centerYAnchor.constraint(equalTo: safeArea.centerYAnchor, constant: -100).isActive = true
view.addSubview(imageView)
imageView.makeTop(equalTo: label.bottomAnchor, constant: 20)
imageView.makeHorizontal(equalTo: view, constant: 30)
imageView.makeHeight(equalTo: label.heightAnchor, constant: 100)
view.addSubview(actionButton)
actionButton.translatesAutoresizingMaskIntoConstraints = false
actionButton.centerXAnchor.constraint(equalTo: label.centerXAnchor).isActive = true
actionButton.topAnchor.constraint(equalTo: imageView.bottomAnchor, constant: 20).isActive = true
actionButton.heightAnchor.constraint(equalToConstant: 60).isActive = true
actionButton.widthAnchor.constraint(equalToConstant: 300).isActive = true
}
func uploadData() {
//헬퍼 함수 예시
}
}
Swift
복사