μ΄ μ€νμΌ κ°μ΄λλ₯Ό μ€μν¨μΌλ‘μ¨
- λ³΄λ€ μ½κ² μ½κ³ μ΅μνμ§ μμ μ½λλ₯Ό μ΄ν΄ν μ μλλ‘ νλ€.
- μ½λλ₯Ό λ³΄λ€ μ½κ² μ μ§ κ΄λ¦¬
- κ°λ¨ν νλ‘κ·Έλλ¨Έ μ€λ₯ κ°μ
- μ½λ© μ μΈμ§ λΆν κ°μ
κ°κ²°ν¨μ΄ μ£Όλ λͺ©νκ° μλλΌλ μ μ μ μνλ€.
μ½λλ λ€λ₯Έ μ’μ μ½λ νμ§(κ°λ
μ±, λ¨μμ±, λͺ
νμ± λ±)μ΄ λμΌνκ² μ μ§λκ±°λ κ°μ λ κ²½μ°μλ§ λ³΄λ€ κ°κ²°νκ² λ§λ€μ΄μΌ νλ€.
- λ³Έ κ°μ΄λμ μλ κ°μ΄λλΌμΈμ μλλ₯Ό λ°λ₯Έλ€.
- λͺ¨λ κ·μΉμ ꡬ체ννκΈ° μν΄ λ Έλ ₯νλ€.
- μμΈμ¬νμ κ±°μ λμ§ μμμΌ νκ³ , μλλΌλ μ λΉμ±μ΄ λμμΌνλ€.
master
λΈλμΉμμfeature
λΈλμΉλ₯Ό λ§λ€μ΄ κ°μ΄λλ₯Ό μμ νκ³ ,master
λΈλμΉλ‘ PRμ λ³΄λ΄ λ¦¬λ·°λ₯Ό ν΅κ³Όνλ©΄ λ°μμν¨λ€.
Tip: μΌλΆ μ½λ λλ λͺ¨λ μ ν(Command-A)ν λ€μ Control-I(λλ νΈμ§κΈ° βΈ Structure βΈ Re-Indent)λ₯Ό μ ννμ¬ λ€μ¬μ°κΈ°λ₯Ό λ€μ ν μ μλ€.
μλ₯Ό λ€μ΄ β// MARK: β¦β λλ β// MARK: - β¦β νμμ μ¬μ©νλ€.
μ’μ μ:
// MARK: Layout
override func layoutSubviews() {
// doSomething()
}
// MARK: Actions
override func menuButtonDidTap() {
// doSomething()
}
μ’μ μ:
var something: Double = 0
var dict = [KeyType: ValueType]()
class MyClass: SuperClass {
// ...
}
λμ μ:
var something : Double = 0
var dict = [KeyType:ValueType]()
var dict = [KeyType : ValueType]()
class MyClass : SuperClass {
// ...
}
μ’μ μ:
func doSomething() -> String {
// ...
}
func doSomething(completion: () -> Void) {
// ...
}
λμ μ:
func doSomething()->String {
// ...
}
func doSomething(completion: ()->Void) {
// ...
}
μ£Όμμ²λ¦¬ μ§μμ΄λ₯Ό μ μΈν TODO:
, FIXME:
μ νμμ μ€μνμ¬ μμ±νλ€.
λ¨, #warning()
ν€μλ μμ μμ±νμ¬ κ°μ λ‘ Warningμ λ°μμν¨λ€.
TODOμ FIXMEλ₯Ό μΆμ νκ³ κ΄λ¦¬νμ¬μΌ νκΈ° λλ¬Έμ΄λ€.
μ’μ μ:
func emptyFunction() {
#warning("TODO: μΆκ° λ‘μ§ μμ± μμ μ
λλ€")
}
#warning("FIXME: νλΌλ―Έν° λͺ
κ΅μ²΄ μμ μ
λλ€")
func doSomething(complexParameterName: String) {
// ...
}
λμ μ:
func emptyFunction() {
// TODO: μΆκ° λ‘μ§ μμ± μμ μ
λλ€
}
// νλΌλ―Έν° λͺ
κ΅μ²΄ μμ μ
λλ€
func doSomething(complexParameterName: String) {
// ...
}
λ©μλ λ° κΈ°ν(if/else/switch/while/guard-else λ±) μ€κ΄νΈλ νμ λ¬Έμ₯κ³Ό λμΌν λΌμΈμμ μ΄λ Έμ§λ§ μλ‘μ΄ λΌμΈμμ λ«νλ€.
μ’μ μ:
if user.isHappy {
// Do something
} else {
// Do something else
}
guard let urlString = urlString, let url = URL(string: urlString) else {
completion(nil, nil)
return
}
λμ μ:
if user.isHappy
{
// Do something
}
else {
// Do something else
}
μμΈ: return
, return nil
μ²λΌ κ°λ¨νκ² guard
λ‘ νμΆνλ κ²½μ° ν μ€λ‘ μμ±νλ€. λ¨, { } μμͺ½μ 곡백μ μ€λ€.
μ’μ μ:
guard let self = self else { return false }
λμ μ:
guard let self = self else {return false}
guard let self = self else {
return false
}
λ©μλ λ΄μ 곡백μ κΈ°λ₯μ λΆλ¦¬ν΄μΌ νμ§λ§ μΉμ μ΄ λ무 λ§μΌλ©΄ μ’ μ’ μ¬λ¬ λ©μλλ‘ λ¦¬ν©ν λ§ν΄μΌνλ€.
ν¨μ μ μ μ 맀κ°λ³μλ νΈμΆ μ μΈμλ κ°μ μ€μ λκ±°λ, μ€ λΉ νλλ§ μκ²νλ€. μ¬λ¬ μ€λ‘ λ§λ λ€λ©΄, κ°κ° μ μ€μ λκ³ λ€μ¬μ°κΈ°λ₯Ό μΆκ°νλ€.
μ’μ μ:
func reticulateSplines(
spline: [Double],
adjustmentFactor: Double,
translateConstant: Int,
comment: String
) -> Bool {
// reticulate code goes here
}
let actionSheet = UIActionSheet(
title: "μ λ§ κ³μ μ μμ νμ€ κ±΄κ°μ?",
delegate: self,
cancelButtonTitle: "μ·¨μ",
destructiveButtonTitle: "μμ ν΄μ£ΌμΈμ"
)
μ’μ μ:
UIView.animate(
withDuration: 0.25,
animations: {
// doSomething()
},
completion: { finished in
// doSomething()
}
)
μ’μ μ:
let evenSquares = numbers.filter { $0 % 2 == 0 }.map { $0 * $0 }
λμ μ:
let evenSquares = numbers.filter {$0 % 2 == 0}.map { $0 * $0 }
μ΄ κ·μΉμ λ²μ μ°μ°μμλ μ μ©λμ§ μλλ€(μ: 1...3
) λ° postfix λλ μ λμ¬ μ°μ°μ (μ: guest?
, -1
).
λ§μ μ°μ°μκ° μλ λ¬Έμ₯μ μκ°μ μΌλ‘ κ·Έλ£ΉννκΈ° μν΄ κ³΅λ°±μ νμ λ€μνκ² νκΈ° 보λ€λ κ΄νΈλ₯Ό μ νΈνλ€.
μ’μ μ:
let capacity = 1 + 2
let capacity = currentCapacity ?? 0
let mask = (UIAccessibilityTraitButton | UIAccessibilityTraitSelected)
let capacity = newCapacity
let latitude = region.center.latitude - (region.span.latitudeDelta / 2.0)
λμ μ:
let capacity = 1+2
let capacity = currentCapacity ?? 0
let mask = (UIAccessibilityTraitButton|UIAccessibilityTraitSelected)
let capacity=newCapacity
let latitude = region.center.latitude - region.span.latitudeDelta/2.0
Tip: μ΄ μ€ν¬λ¦½νΈλ₯Ό μ€ννμ¬ Xcodeμμ μΌλΆ μ€μ μ νμ±νν μ μλ€. μ: "Run Script" build phaseμ μΌλΆκ° λκ² νλ©΄λλ€.
λͺ λͺ μ κΈ°λ³Έμ μΌλ‘ Swift API Design Guidelinesμ κ°μ΄λλ₯Ό λ°λ₯Έλ€. μ λ¬Έμμ λ΄μ©μ μ¬κΈ°μ μ 리ν μ λ μκ³ , μλ‘μ΄ κ°μ΄λλΌμΈμ μΆκ°ν μλ μλ€.
νμ
κ³Ό νλ‘ν μ½ μ΄λ¦μ PascalCaseλ₯Ό μ¬μ©νκ³ , κ·Έ μΈμλ lowerCamelCase λ₯Ό μ¬μ©νλ€.
μ’μ μ:
protocol SpaceThing {
// ...
}
class SpaceFleet: SpaceThing {
enum Formation {
// ...
}
class Spaceship {
// ...
}
var ships: [Spaceship] = []
static let worldName: String = "Earth"
func addShip(_ ship: Spaceship) {
// ...
}
}
let myFleet = SpaceFleet()
μμΈ: λμΌν μ΄λ¦μ μμ±μ΄λ λ©μλκ° λ λμ μ‘μΈμ€ μμ€μ κ°μ§ κ²½μ°, private
μμ±μ λ°μ€ μ λμ¬λ₯Ό λΆμΌ μ μλ€.
μμ±μ΄λ λ©μλλ₯Ό backingνλ κ²μ΄ μ€λͺ μ μΈ μ΄λ¦μ μ¬μ©νλ κ² λ³΄λ€ λ μ½κΈ° μ¬μΈ μ μλ€. μλ₯Ό λ€μ΄
μ’μ μ:
- Type erasure
public final class AnyRequester<ModelType>: Requester {
public init<T: Requester>(_ requester: T) where T.ModelType == ModelType {
_executeRequest = requester.executeRequest
}
@discardableResult
public func executeRequest(
_ request: URLRequest,
onSuccess: @escaping (ModelType, Bool) -> Void,
onFailure: @escaping (Error) -> Void) -> URLSessionCancellable
{
return _executeRequest(request, session, parser, onSuccess, onFailure)
}
private let _executeRequest: (
URLRequest,
@escaping (ModelType, Bool) -> Void,
@escaping (NSError) -> Void) -> URLSessionCancellable
}
- λ ꡬ체μ μΈ νμ μ μ¬μ©νμ¬ λ ꡬ체μ μΈ νμ μ backingνλ€.
final class ExperiencesViewController: UIViewController {
// We can't name this view since UIViewController has a view: UIView property.
private lazy var _view = CustomView()
loadView() {
self.view = _view
}
}
μ΄κ²μ κ·Έλ€μ΄ λ€λ₯Έ νμ μ΄ μλ booleanμ΄λΌλ κ²μ λΆλͺ ν νλ€.
μ½μ΄λ‘ μμνλ κ²½μ° μλ¬Έμλ‘ νκΈ°νκ³ , κ·Έ μΈμ κ²½μ°μλ νμ λλ¬Έμλ‘ νκΈ°νλ€.
μ’μ μ:
class URLValidator {
func isValidURL(_ url: URL) -> Bool {
// ...
}
func isProfileURL(_ url: URL, for userID: String) -> Bool {
// ...
}
}
let urlValidator = URLValidator()
let isProfile = urlValidator.isProfileURL(urlToTest, userID: idOfUser)
λμ μ:
class UrlValidator {
func isValidUrl(_ URL: URL) -> Bool {
// ...
}
func isProfileUrl(_ URL: URL, for userId: String) -> Bool {
// ...
}
}
let URLValidator = UrlValidator()
let isProfile = URLValidator.isProfileUrl(URLToTest, userId: IDOfUser)
μ΄λ¦μ κ°μ₯ μΌλ°μ μΈ λΆλΆμ λ¨Όμ μ°κ³ κ°μ₯ ꡬ체μ μΈ λΆλΆμ λ§μ§λ§μ μ¨μΌ νλ€.
"κ°μ₯ μΌλ°μ μΈ"μ μλ―Έλ μν©μ λ°λΌ λ€λ₯΄μ§λ§ λλ΅μ μΌλ‘ "μ°Ύλ νλͺ©μ λν κ²μ λ²μλ₯Ό μ’νλ λ° κ°μ₯ λμμ΄ λλ" κ²μ μλ―Έν΄μΌ νλ€. κ°μ₯ μ€μν κ²μ μΌκ΄μ±μ μ§ν€λ κ²μ΄λ€.
μ’μ μ:
let titleMarginRight: CGFloat
let titleMarginLeft: CGFloat
let bodyMarginRight: CGFloat
let bodyMarginLeft: CGFloat
λμ μ:
let rightTitleMargin: CGFloat
let leftTitleMargin: CGFloat
let bodyRightMargin: CGFloat
let bodyLeftMargin: CGFloat
μ’μ μ:
let titleText: String
let cancelButton: UIButton
λμ μ:
let title: String
let cancel: UIButton
μ£Όμ΄κ° λͺ ννλ€λ©΄ μλ΅ν μ μλ€.
μ’μ μ:
class ExperiencesViewController {
private func didTapBookButton() {
// ...
}
private func modelDidChange() {
// ...
}
}
λμ μ:
class ExperiencesViewController {
private func handleBookButtonTap() {
// ...
}
private func modelChanged() {
// ...
}
}
μ΄λ¦κ° μΆ©λμ νΌνκΈ° μν λ°©μμ΄μλλ° Swiftμμ λ μ΄μ νμνμ§ μλ€. μ€μννΈμ νμ
μ ν΄λΉ νμ
μ ν¬ν¨νλ λͺ¨λμ μν΄ μλμΌλ‘ λ€μμ€νμ΄μ€κ° μ§μ λλ©°, NS
μ κ°μ ν΄λμ€ μ λμ¬λ₯Ό μΆκ°ν΄μλ μ λλ€. μλ‘ λ€λ₯Έ λͺ¨λμ λ μ΄λ¦μ΄ μΆ©λνλ κ²½μ° μ ν μ΄λ¦κ³Ό λͺ¨λ μ΄λ¦μ μ λμ¬λ‘ μ°κ²°νμ¬ λͺ¨νΈν μ 보λ₯Ό ν΄μ ν μ μλ€. λ¨, νΌλ κ°λ₯μ±μ΄ μμ λλ§ λͺ¨λ μ΄λ¦μ μ§μ νλ€.
μ’μ μ:
class Account {
// ...
}
λμ μ:
class AIRAccount {
// ...
}
Delegate methodλ₯Ό λ§λ€ λ μ΄λ¦ μλ 첫 λ²μ§Έ λ§€κ° λ³μκ° delegate sourceκ° λμ΄μΌ νλ€.
μ’μ μ:
func namePickerView(_ namePickerView: NamePickerView, didSelectName name: String)
func namePickerViewShouldReload(_ namePickerView: NamePickerView) -> Bool
λμ μ:
func didSelectName(namePicker: NamePickerViewController, name: String)
func namePickerShouldReload() -> Bool
μ’μ μ:
func name(for user: User) -> String?
λμ μ:
func getName(for user: User) -> String?
λ·°(UIView
λ° νμ νμ
)νμ
λ³μμ μ΄λ¦μ μ§μ λ νμ
μ΄λ¦μ λ€μ λΆμ¬μ€λ€.
νμ
μ΄λ¦μ μ€μ΄μ§ μλλ€. UICollectionViewCell
, UITableViewCell
μ κ²½μ°λ λ무 κΈΈκΈ° λλ¬Έμ Cell
λ§ νμ©νλ€.
μ΄λ€ κΈ°λ₯μ λ·°μΈμ§ λ°λ‘ μ μ μμ΄μ κ°λ μ±μ΄ μ’μμ§λ€.
μ’μ μ:
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var moreButton: UIButton!
@IBOutlet weak var collectionView: UICollectionView!
@IBOutlet weak var bannerCell: UITableViewCell!
λμ μ:
@IBOutlet weak var title: UILabel!
@IBOutlet weak var moreBtn: UIButton!
@IBOutlet weak var collection: UICollectionView!
@IBOutlet weak var bannerTableViewCell: UITableViewCell!
λ λΉ λ₯΄κ² μ΄λ¦μ μ§μμ μκ³ , ν μ€νΈλ₯Ό μ΄ν΄ν μ μλ€. νκΈλ‘ μμ±νλ©΄ μ¬λ°λ₯Έ ν μ€νΈμΈμ§ νλ¨νκΈ°κ° λ μ½λ€.
μ’μ μ:
let host = Host()
let selector = #selector(viewDidLoad)
view.backgroundColor = .red
let toView = context.view(forKey: .to)
let view = UIView(frame: .zero)
λμ μ:
let host: Host = Host()
let selector = #selector(ViewController.viewDidLoad)
view.backgroundColor = UIColor.red
let toView = context.view(forKey: UITransitionContextViewKey.to)
let view = UIView(frame: CGRect.zero)
μΈμ΄μ μν΄ μꡬλκ±°λ λͺ¨νΈν¨μ νΌνκΈ° μν κ²½μ°κ° μλλΌλ©΄ self
λ₯Ό μ¬μ©νμ§ μλλ€.
μ’μ μ:
final class Listing {
init(capacity: Int, allowsPets: Bool) {
self.capacity = capacity
isFamilyFriendly = !allowsPets
}
private let isFamilyFriendly: Bool
private var capacity: Int
private func increaseCapacity(by amount: Int) {
capacity += amount
save()
}
}
λμ μ:
final class Listing {
init(capacity: Int, allowsPets: Bool) {
self.capacity = capacity
self.isFamilyFriendly = !allowsPets // `self.` not required here
}
private let isFamilyFriendly: Bool
private var capacity: Int
private func increaseCapacity(by amount: Int) {
self.capacity += amount
self.save()
}
}
μ’μ μ:
class MyClass {
func request(completion: () -> Void) {
API.request() { [weak self] response in
guard let self = self else { return }
// Do work
completion()
}
}
}
λμ μ:
class MyClass {
func request(completion: () -> Void) {
API.request() { [weak self] response in
guard let strongSelf = self else { return }
// Do work
completion()
}
}
}
κ²½νμ 3κ° μ΄μμ νλκ° μλ€λ©΄, μλ§ structλ₯Ό μ¬μ©ν΄μΌ ν κ²μ΄λ€.
μ’μ μ:
func whatever() -> (x: Int, y: Int) {
return (x: 4, y: 4)
}
let coord = whatever()
coord.x
coord.y
λμ μ:
func whatever() -> (Int, Int) {
return (4, 4)
}
let thing = whatever()
print(thing.0)
μ’μ μ:
if userCount > 0 { ... }
switch someValue { ... }
let evens = userCounts.filter { number in number % 2 == 0 }
let squares = userCounts.map { $0 * $0 }
λμ μ:
if (userCount > 0) { ... }
switch (someValue) { ... }
let evens = userCounts.filter { (number) in number % 2 == 0 }
let squares = userCounts.map() { $0 * $0 }
μ’μ μ:
let range = NSRange(location: 10, length: 5)
λμ μ:
let range = NSMakeRange(10, 5)
μ»΄νμΌ μκ°μ μν₯μ μ£Όλ μ£Όμ μμΈμ΄λ―λ‘ μ§μνλ€.
μ’μ μ:
let firstName = "κΉ"
let secondName = "ν°λ"
let wholeName = "\(firstName)\(secondName)"
λμ μ:
let firstName = "κΉ"
let secondName = "ν°λ"
let wholeName = firstName+secondName
κ°λ μ±μ΄ ν₯μλλ€.
μ’μ μ:
let completionBlock: (() -> Void)?
λμ μ:
let completionBlock: (() -> ())?
let completionBlock: ((Void) -> (Void))?
μ΄λ€ 맀κ°λ³μκ° μ¬μ©λκ³ μ΄λ€ 맀κ°λ³μκ° μ¬μ©λμ§ μλμ§ λͺ νν ν¨μΌλ‘μ¨ closureλ₯Ό μ½μ λ νμν μΈμ§ μ€λ²ν€λκ° κ°μνλ€.
μ’μ μ:
someAsyncThing() { _, _, argument3 in
print(argument3)
}
λμ μ:
someAsyncThing() { argument1, argument2, argument3 in
print(argument3)
}
closure 맀κ°λ³μκ° λ§μ§λ§ λμ νλ μλ€λ©΄ κ°λ₯ν ν trailing closure ꡬ문μ μ¬μ©νλ€.
λ μ΄μμ΄λΌλ©΄ νλ²νκ² μ¬μ©νλ€.
μ’μ μ:
UIView.animate(withDuration: 1.0) {
self.myView.alpha = 0
}
UIView.animate(withDuration: 1.0, animations: {
self.myView.alpha = 0
}, completion: { finished in
self.myView.removeFromSuperview()
})
λμ μ:
UIView.animate(withDuration: 1.0, animations: {
self.myView.alpha = 0
})
UIView.animate(withDuration: 1.0, animations: {
self.myView.alpha = 0
}) { f in
self.myView.removeFromSuperview()
}
μ’μ μ:
var diameter: Double {
return radius * 2
}
λμ μ:
var diameter: Double {
get {
return radius * 2
}
}
μ’μ μ:
var messages: [String]?
var names: [Int: String]?
λμ μ:
var messages: Array<String>?
var names: Dictionary<Int, String>?
? λ regular optionals μ μλ―Ένλ€.
! λ implicitly unwrapped optionals (μ묡μ μΌλ‘ ν¬μ₯μ΄ ν리λ μ΅μ λ)μ μλ―Ένλ€. κ°μ΄λμμλ ? μ ! λ‘ λ체νμ¬ νννλ€.
κ°λ₯ν ν ? λ‘ μ μΈνλ€. μ¬μ©μ λ°λμ μ΄κΈ°νλλ κ²½μ°μλ§ ! λ‘ μ μΈνλ€.
! λ λ°νμμ ν¬λμμ μμΈμ΄ λ μ μλ€.
-
κ·Έλ¬λ, λΌμ΄ννμμ΄ UI λΌμ΄νμ¬μ΄ν΄μμ μλ μ¬μ©μ μΈν°νμ΄μ€ κ°μ²΄λ ! λ₯Ό μ¬μ©ν μ μλ€. μλνλ©΄ κ·Έκ²λ€μ no-nilμ΄ λ³΄μ₯λκΈ° λλ¬Έμ΄λ€.
- XIB νμΌμ΄λ μ€ν 리보λμ κ°μ²΄μ μ°κ²°λ
@IBOutlet
μμ±, μΈλΆμμ μ£Όμ λλ μμ± λ± κ·Έλ¬ν μμ±μ ? λ‘ λ§λλ κ²μ μ¬μ©μκ° ν¬μ₯μ νκΈ°μλ λ무 λ§μ λΆλ΄μ μ€ μ μλ€.
- XIB νμΌμ΄λ μ€ν 리보λμ κ°μ²΄μ μ°κ²°λ
-
λν ! λ λ¨μν μ€νΈμμ νμ©λλ€. μ΄λ μμ UI κ°μ²΄ μλ리μ€μ μ μ¬ν μ΄μ λλ¬Έμ΄λ€.
- ν
μ€νΈ fixtureμ μλͺ
μ μ’
μ’
ν
μ€νΈμ μ΄κΈ°νν¨μκ° μλλΌ ν
μ€νΈμ
setUp()
λ©μλμμ μμνμ¬ κ° ν μ€νΈλ₯Ό μ€ννκΈ° μ μ μ¬μ€μ ν μ μλ€.
- ν
μ€νΈ fixtureμ μλͺ
μ μ’
μ’
ν
μ€νΈμ μ΄κΈ°νν¨μκ° μλλΌ ν
μ€νΈμ
μ’μ μ:
textContainer?.textLabel?.setNeedsDisplay()
μ΅μ λ λ°μΈλ©μ μ¬μ©νλ λμ nilμ 체ν¬νλ©΄ κ·Έ μ€νλ¬Έμ μλκ° λ¬΄μμΈμ§ μ¦μ μ μ μλ€.
μ’μ μ:
var thing: Thing?
if nil != thing {
doThing()
}
λμ μ:
var thing: Thing?
if let _ = thing {
doThing()
}
μ£Όμμ κΈ°λ³Έμ μΌλ‘ Swift API Design Guidelines μ κ°μ΄λλ₯Ό λ°λ₯Έλ€. μ λ¬Έμμ λ΄μ©μ μ¬κΈ°μ μ 리ν μ λ μκ³ , μλ‘μ΄ κ°μ΄λλΌμΈμ μΆκ°ν μλ μλ€.
κ°μ μΈλ©ν μ΅μ
μ μ¬μ©νμ§ μκ³ κ°λ₯νλ©΄ init
νμμ μμ±μ μ΄κΈ°ννλ κ²μ μ νΈνλ€.
λλλ¬μ§ μμΈλ UIViewControllerμ view
μμ±μ΄λ€.
μ’μ μ:
class MyClass: NSObject {
init() {
someValue = 0
super.init()
}
var someValue: Int
}
λμ μ:
class MyClass: NSObject {
init() {
super.init()
someValue = 5
}
var someValue: Int!
}
λ°μ΄ν°λ² μ΄μ€ μ°κ²° μ΄κΈ°, λ€νΈμν¬ μμ², λμ€ν¬μμ λλμ λ°μ΄ν° μ½κΈ° λ±μ μμ
μ μννμ§ μλλ€. κ°μ²΄λ₯Ό μ¬μ©ν μ€λΉκ° λκΈ° μ μ μ΄λ¬ν μμ
μ μνν΄μΌ νλ κ²½μ° start()
λ©μλκ³Ό κ°μ κ²μ λ§λ λ€.
μ΄λ μ€μ²©μ±μ κ°μμν€κ³ , μμ± μ μΈμΌλ‘ λΆν° μ¬μ΄λμ΄ννΈλ₯Ό λΆλ¦¬ν΄λ΄κ³ , oldValue
μ κ°μ΄ μ묡μ μΌλ‘ μ λ¬λλ 맀κ°λ³μλ₯Ό λͺ
μμ μΌλ‘ μ¬μ©νκ² λ§λ λ€.
μ’μ μ:
class TextField {
var text: String? {
didSet { textDidUpdate(from: oldValue) }
}
private func textDidUpdate(from oldValue: String?) {
guard oldValue != text else {
return
}
// Do a bunch of text-related side-effects.
}
}
λμ μ:
class TextField {
var text: String? {
didSet {
guard oldValue != text else {
return
}
// Do a bunch of text-related side-effects.
}
}
}
μ΄κ²μ weak-selfκ° μΌκΈ°νλ 볡μ‘μ±μ λ§κ³ μ€μ²©μ±μ κ°μμν¨λ€.
μ’μ μ:
class MyClass {
func request(completion: () -> Void) {
API.request() { [weak self] response in
guard let self = self else { return }
self.doSomething(with: self.property, response: response)
completion()
}
}
func doSomething(with nonOptionalParameter: SomeClass, response: SomeResponseClass) {
// Processing and side effects
}
}
λμ μ:
class MyClass {
func request(completion: () -> Void) {
API.request() { [weak self] response in
if let self = self {
// Processing and side effects
}
completion()
}
}
}
λͺ¨λ guard
λ¬Έμ μλ¨μ λͺ¨μλλ κ²μ΄ λΉμ¦λμ€ λ‘μ§κ³Ό μμΌλ code blockμ λν΄ μΆλ‘ νλ κ²μ΄ λ μ½λ€.
νμΆ μ‘°κ±΄μμ throws
λ return
λ¬Έ λ±μ μ€ννκ±°λ μ΅μ
λ λ°μΈλ©μ ν΄μΌν λ guard
λ¬Έμ μ¬μ©νλ©΄ μ€μ²©λλ₯Ό μ€μ¬μ κ°λ
μ±κ³Ό μ μ§λ³΄μμ±μ λμΌ μ μλ€.
μ’μ μ:
func computeFFT(context: Context?, inputData: InputData?) throws -> Frequencies {
guard let context = context else {
throw FFTError.noContext
}
guard let inputData = inputData else {
throw FFTError.noInputData
}
// use context and input to compute the frequencies
return frequencies
}
guard
let number1 = number1,
let number2 = number2,
let number3 = number3
else {
fatalError("impossible")
}
// do something with numbers
λμ μ:
func computeFFT(context: Context?, inputData: InputData?) throws -> Frequencies {
if let context = context {
if let inputData = inputData {
// use context and input to compute the frequencies
return frequencies
} else {
throw FFTError.noInputData
}
} else {
throw FFTError.noContext
}
}
if let number1 = number1 {
if let number2 = number2 {
if let number3 = number3 {
// do something with numbers
} else {
fatalError("impossible")
}
} else {
fatalError("impossible")
}
} else {
fatalError("impossible")
}
μ¬λ¬ μ’
λ£μ§μ μμ μ 리 μ½λκ° νμν κ²½μ° defer
blockμ μ¬μ©νλ κ²μ κ³ λ €νλ€.
κ·Έλ° νλμ΄ νμνμ§ μλ ν open
보λ€λ public
, fileprivate
보λ€λ private
μͺ½μ μ νΈνλ€.
μ’μ μ:
class TimeMachine {
private dynamic lazy var fluxCapacitor = FluxCapacitor()
}
λμ μ:
class TimeMachine {
lazy dynamic private var fluxCapacitor = FluxCapacitor()
}
μμΈ: static
μ§μ μλ @IBAction
, @IBOutlet
, @discardableResult
κ°μ attributes
νμ§λ§, νμ
μ μ λ΄μμλ κ°μ μμ€μ μ κ·Όμ μ΄λ₯Ό μλ΅νλ€.
λͺ μμ μΌλ‘ νμνκ² λλ©΄ νμ μ μ€νκ² κ²°μ νκ² λλ€. μ μ λ΄μμ λμΌν μ κ·Ό μ μ΄ μ§μ μλ₯Ό μ¬μ¬μ©νλ κ²μ μ€λ³΅μ΄λ©°, μΌλ°μ μΌλ‘ κΈ°λ³Έκ°μ΄ ν©λΉνλ€.
μ’μ μ:
puplic struct Book {}
internal apiKey : String
private func change(options: [Option]) {}
public class ImageDownloader {
var links = ImageLinks()
private var queue = OperationQueue()
}
λμ μ:
struct Book {}
apiKey : String
func change(options: [Option]) {}
public class ImageDownloader {
public var links = ImageLinks()
private var queue = OperationQueue()
}
μ’μ μ:
private extension ViewController {
private func setupViews() {}
}
λμ μ:
private extension ViewController {
func setupViews() {}
}
νμ μ μμμμ λ©μλλ₯Ό μ μνλ κ²μ μ νΈνλ€.
μ΄κ²μ κ°λ μ±μ λμμ΄ λλ€. λ 빨리 μ°Ύμ μ μλ€. μ μ ν¨μλ νΉμ νμ μ΄λ μΈμ€ν΄μ€μ κ΄λ ¨μ΄ μμ λ κ°μ₯ μ μ νλ€.
μ’μ μ:
class Person {
var bornAt: TimeInterval
var age: Int {
// ...
}
func jump() {
// ...
}
}
λμ μ:
func age(of person, bornAt timeInterval) -> Int {
// ...
}
func jump(person: Person) {
// ...
}
public
λλ internal
μΈ κ²½μ° namespacing μ μν΄ static
μμ±μΌλ‘ μ μνλ€.
μ’μ μ:
private let privateValue = "secret"
public class MyClass {
public static let publicValue = "something"
func doSomething() {
print(privateValue)
print(MyClass.publicValue)
}
}
public
λλ internal
μμ λ° ν¨μλ₯Ό λ€μμ€νμ΄μ€λ‘ λ¬Άκ³ μΆμ λλ case
μλ enum
μ μ¬μ©νλ€.
λ€μμ€νμ΄μ€ μμ΄ μ μ μμμ ν¨μλ₯Ό λ§λ€μ§ μλλ€. λͺ
λ£ν¨μ μν΄μλΌλ©΄ λ€μμ€νμ΄μ€λ₯Ό μ νμμ΄ μ€μ²©νλ€.
case
μλ enum
μ μΈμ€ν΄μ€λ‘ λ§λ€ μ μκΈ° λλ¬Έμ μμν λ€μμ€νμ΄μ€λ‘ μ λ§λλ€.
μ’μ μ:
enum Environment {
enum Earth {
static let gravity = 9.8
}
enum Moon {
static let gravity = 1.6
}
}
μΈλΆ μμ€λ‘ λΆν° 맀νλλ κ²½μ°κ° μλλΌλ©΄, Swiftμ μλμΌλ‘ 맀겨μ§λ enum κ°μ κ·Έλλ‘ μ¬μ©νλ€.
κ°μ λͺ μμ μΌλ‘ ν λΉνλ€λ©΄ κ·Έ μ΄μ λ₯Ό μ€λͺ νλ commentλ₯Ό μΆκ°νλ€.
μ¬μ©μ μ€λ₯λ₯Ό μ΅μννκ³ κ°λ
μ±μ ν₯μμν€λ©° μ½λλ₯Ό λ 빨리 μ°λ €λ©΄ Swiftμ μλ enum
κ°μ μ¬μ©νλ€. κ·Έλ¬λ κ°μ΄ μΈλΆ μμ€μ 맀νλκ±°λ(μ: λ€νΈμν¬ μμ²μμ μ 곡λ¨) λ°μ΄λ리 μ μμ κ±Έμ³ μ¬λΌμ§μ§ μκ³ μ μ§λλ κ²½μ°, λͺ
μμ μΌλ‘ κ°μ μ μνκ³ μ΄ κ°μ΄ 맀νλλ λμμ λ¬Έμννλ€. μ΄λ κ²νλ©΄ λκ΅°κ°κ° μ€κ°μ μλ‘μ΄ κ°μ μΆκ°νλ€κ³ ν΄λ κΈ°μ‘΄ κ²μ κΉ¨λ¨λ¦¬μ§ μκ² λλ€.
μ’μ μ:
enum ErrorType: String {
case error
case warning
}
/// μ΄κ²μ logging serviceμμ μ¬μ©λλ€. λͺ
μμ μΈ κ°μ λ°μ΄λ리 μ μμ κ±Έμ³ μΌκ΄μ±μ 보μ₯νλ€.
// swiftlint:disable redundant_string_enum_value
enum UserType: String {
case owner = "owner"
case manager = "manager"
case member = "member"
}
// swiftlint:enable redundant_string_enum_value
enum Planet: Int {
case mercury
case venus
case earth
case mars
case jupiter
case saturn
case uranus
case neptune
}
/// μ΄λ¬ν κ°μ μλ²μμ μ 곡νλ―λ‘, μ¬κΈ°μ λͺ
μμ μΌλ‘ 맀μΉλλ κ°μ μ€μ νλ€.
enum ErrorCode: Int {
case notEnoughMemory = 0
case invalidResource = 1
case timeOut = 2
}
λμ μ:
enum ErrorType: String {
case error = "error"
case warning = "warning"
}
enum UserType: String {
case owner
case manager
case member
}
enum Planet: Int {
case mercury = 0
case venus = 1
case earth = 2
case mars = 3
case jupiter = 4
case saturn = 5
case uranus = 6
case neptune = 7
}
enum ErrorCode: Int {
case notEnoughMemory
case invalidResource
case timeOut
}
μμΈ: Codableμ μ€μνλ νμ μ κ²½μ° λ΄λΆμ enum caseμμλ λͺ μμ μΈ κ°μ μ μνλ€
μ 컬λ μ
μ μΆκ°νλ λμ map
κ³Ό compactMap
μ μ¬μ©νλ€. λ³κ²½ κ°λ₯ν 컬λ μ
μμ μμλ₯Ό μ κ±°νλ λμ filter
λ₯Ό μ¬μ©νλ€.
mutable λ³μλ 볡μ‘μ±μ μ¦κ°μν€λ―λ‘ κ°λ₯ν ν λ²μλ₯Ό μ’νλλ‘ νλ€.
μ’μ μ:
let results = input.map { transform($0) }
let results = input.compactMap { transformThatReturnsAnOptional($0) }
λμ μ:
var results = [SomeType]()
for element in input {
let result = transform(element)
results.append(result)
}
var results = [SomeType]()
for element in input {
if let result = transformThatReturnsAnOptional(element) {
results.append(result)
}
}
λ©μλλ₯Ό μ¬μ μν΄μΌνλ κ²½μ°μλ class
ν€μλλ₯Ό μ¬μ©νλ€.
μ’μ μ:
class Fruit {
static func eatFruits(_ fruits: [Fruit]) { ... }
}
λμ μ:
class Fruit {
class func eatFruits(_ fruits: [Fruit]) { ... }
}
ν΄λμ€λ₯Ό μ¬μ μν΄μΌνλ κ²½μ°μλ final
ν€μλλ₯Ό μλ΅νλ€.
νΈμΆν
class
ꡬν체λ₯Ό μ ννλ κ³Όμ μ λ°νμ λ¨κ³μμ μνλλ©°, μ΄λ dynamic dispatchλ‘ μλ €μ Έμλ€. λ°νμ μ€λ²ν€λμ μΌμ λΆλΆμ ν΄λμ€ μμμ μ¬μ©νλ κ²κ³Ό κ΄λ ¨μ΄ μλ€.final
ν€μλλ λ©μλλ ν¨μμ κ²½μ° μ€λ²λΌμ΄λ ν μ μκ² νκ³ , ν΄λμ€λ μλΈν΄λμ± ν μ μκ² νλ€. μ΄ ν€μλλ λ°νμμμ λ©μλλ μμ±μ μ§μ νΈμΆν μ μκ² ν΄μ€ κ²μ΄λ©°, μ½κ°μ μ±λ₯ ν₯μμ κ°μ Έμ¨λ€. μ€μννΈ 4 νλ‘ν μ½μ§ν₯ νλ‘κ·Έλλ° 3/e μμ μμ½ μΈμ©
μ’μ μ:
final class SettingsRepository {
// ...
}
λμ μ:
class SettingsRepository {
// ...
}
λͺ¨λ case
λ₯Ό μ΄κ±°νλ κ²μ κ°λ°μμ κ²ν μκ° μλ‘μ΄ case
κ° μΆκ°λ λ λͺ¨λ switch
λ¬Έμ₯μ μ νμ±μ κ³ λ €νλλ‘ ν΄μ€λ€.
μ’μ μ:
switch anEnum {
case .a:
// Do something
case .b, .c:
// Do something else.
}
λμ μ:
switch anEnum {
case .a:
// Do something
default:
// Do something else.
}
switch
λ¬Έμμ case
λ΄ μ²λ¦¬ν΄μΌ ν μ½λκ° μλ κ²½μ°μλ break
μ¬μ©νμ§ μλλ€.
case
λ΄ μ²λ¦¬ν΄μΌ ν μ½λκ° μλ κ²½μ°, case
λ΄μ μμ±λ break
λ μ»΄νμΌλ¬μκ² μΌλ§ μΆκ° μν€κ³ , μ€νλλ μλ―Έλ μλ μ½λκ° λμ΄λ²λ¦°λ€.
μ’μ μ:
switch anEnum {
case .a:
// Do something
case .b, .c:
// Do something else.
}
λμ μ:
switch anEnum {
case .a:
// Do something
break
default:
// Do something
break
}
μ’μ μ:
["1", "2", "3"].compactMap { Int($0) }
var size: CGSize {
CGSize(
width: 100.0,
height: 100.0)
}
func makeInfoAlert(message: String) -> UIAlertController {
UIAlertController(
title: "βΉοΈ Info",
message: message,
preferredStyle: .alert)
}
λμ μ:
["1", "2", "3"].compactMap { return Int($0) }
var size: CGSize {
return CGSize(
width: 100.0,
height: 100.0)
}
func makeInfoAlert(message: String) -> UIAlertController {
return UIAlertController(
title: "βΉοΈ Info",
message: message,
preferredStyle: .alert)
}
λ§ν΄νμΈλ¬μ GivenWhenThen ꡬκΈλ§μΌλ‘ μ¬λ¬ λ²μλ³Έμ μ°Ύμ μ μμ΅λλ€.
μ’μ μ:
var isMember: Bool {
MemberManager.shared.isMember
}
λμ μ:
func isMember() -> Bool {
MemberManager.shared.isMember
}
κ°μ²΄μ public interfaceλ₯Ό μ μν λ λ°λ₯΄λ κ°μ΄λλΌμΈ
Law of Demeter. λ―μ μμκ² λ§νμ§ λ§κ³ , μ€μ§ μΈμ ν μ΄μνκ³ λ§ λ§νλΌ.
λλ―Έν° λ²μΉμ λ°λ₯΄λ μ½λλ λ©μμ§ μ μ‘μκ° μμ μμ λ΄λΆ ꡬνμ κ²°ν©λμ§ μλλ€.
λλ―Έν° λ²μΉμ μλ°ν μ½λλ₯Ό μμ νλ μΌλ°μ μΈ λ°©λ²μ λ¬»μ§ λ§κ³ μμΌλΌ
λ₯Ό λ°λ₯΄λ κ²μ΄λ€. κ°μ²΄μκ² λ΄λΆ ꡬ쑰λ₯Ό 묻λ λμ μ§μ μμ μ μ±
μμ μννλλ‘ μν€λ κ²μ΄λ€.
μ΄ λ μ€νμΌμ λ°λ₯΄λ©΄ μμ°μ€λ½κ² μμ¨μ μΈ κ°μ²΄λ‘ ꡬμ±λ μ μ°ν νλ ₯μ μ»κ² λλ€.
μ’μ μ:
public class ReservationAgency {
func func reserve(screening: Screening, customer: Customer, audienceCount: Int) -> Reservation {
let fee = screening.calculateFee(audienceCount)
Reservation(customer, screening, fee, audienceCount);
}
}
λμ μ:
public class ReservationAgency {
func reserve(screening: Screening, customer: Customer, audienceCount: Int) -> Reservation {
let movie: Movie = screening.movie
var fee: Int = 0
if movie.isDiscountable {
let discountAmount = movie.discountAmount
fee = (movie.fee - discountAmount) * audienceCount
} else {
fee = movie.fee * audienceCount
}
return Reservation(customer, screening, fee, audienceCount);
}
}
μμΈ: self μμ±μ 컬λ μ μμμλ λ©μμ§λ₯Ό μ μ‘ν΄λ μ’λ€.
μμΈ: λλ―Έν°λ²μΉμ νλμ μ μ κ°μ νλ κ·μΉμ΄ μλλ€
μλ μ½λλ λλ―Έν°λ²μΉμ μλ°°νμ§ μλλ€. κ°μ²΄μ λ΄λΆμ λν μ΄λ€ λ΄μ©λ λ¬»μ§ μλλ€.
[1, 10, 99, 101, 1000].filter{ $0 > 100 }.map{ $0 * 10 }.first
κ°μ²΄μ λ΄λΆ κ΅¬μ‘°κ° λ ΈμΆλμ§ μλλ€λ©΄ λ²μΉμ μ€μν κ²μ΄λ€.
μμ±μ private
μΌλ‘ λ§λ€μ΄μ μ§μ μ κ·Όνμ§ μκ³ , λ©μλλ§ μ¬μ©νλ€.
λ¬»μ§ λ§κ³ μμΌλΌ (Tell, Don't Ask) μμΉ. κ°μ²΄μ μνμ κ΄ν΄ λ¬»μ§ μκ³ μνλ κ²μ μν¨λ€.
μ΄λ κ² νλ©΄ κ°μ²΄μ λν΄μ μμμΌν μ 보λ₯Ό μ΅μνν μ μλ€. κ·Έλ¦¬κ³ , μμ°μ€λ½κ² κ΄λ ¨ μ 보λ₯Ό κ°μ₯ μ μκ³ μλ κ°μ²΄μκ² μ± μμ ν λΉν μ μλ€. μΈλΆμμ κ°μ²΄μ μνλ₯Ό κΈ°λ°μΌλ‘ κ²°μ μ λ΄λ¦¬κ² λλ©΄ μΊ‘μνλ₯Ό μλ°νκ² λλ€.
μμΈ:
- 묻λ κ² μ΄μΈμλ λ€λ₯Έ λ°©λ²μ΄ μ‘΄μ¬νμ§ μλ κ²½μ°λ μλ€. κ°μ²΄μκ² λ¬»μ§μκ³ μ§μ κ·Έ μΌμ νλλ‘ νλ κ²½μ° μμ§λλ λμμ§ μ μμ§λ§, λ³Έμ§μ μ΄μ§ μλ μ± μμ λ μκ² λμ΄ κ°μ²΄κ° κ²°ν©λκ° λμμ§μ μλ€.
- λ¬ΌμΌλ €λ κ°μ²΄κ° μ λ§λ‘ λ°μ΄ν°μΈ κ²½μ°λ μλ€.
- μλ£κ΅¬μ‘°λΌλ©΄ λΉμ°ν λ΄λΆλ₯Ό λ ΈμΆν΄μΌνλ―λ‘ λλ―Έν° λ²μΉμ μ μ©ν νμκ° μλ€.
μμ±μ μ§μ μ κ·Όν΄μΌνλ€λ©΄ readonlyλ‘ λ§λ€μ΄μ μΈλΆμμ μ§μ μμ ν μ μκ² νλ€. μμ±κ° μμ μ΄ νμνλ©΄ λ©μλλ₯Ό ν΅ν΄μλ§ κ°λ₯νκ²νλ€.
μ’μ μ:
public struct Movie {
private(set) isDiscountable: Bool
private(set) discountAmount: Int
private(set) fee: Int
}
λμ μ:
public struct Movie2 {
var isDiscountable: Bool
var discountAmount: Int
var fee: Int
}
λ©μλμ μ΄λ¦μ 'μ΄λ»κ²'κ° μλλΌ ν΄λΌμ΄μΈνΈκ° '무μ'μ μνλμ§λ₯Ό λλ¬λ΄λλ‘ μ§λλ€.
- 'μ΄λ»κ²'λ λ΄λΆ ꡬνμ μ€λͺ νλ©°, μ€κ³ μμ μ λ΄λΆ ꡬνμ λν΄ κ³ λ―Όν μ λ°μ μλ€. κ²°κ³Όμ λͺ©μ λ§μ ν¬ν¨νλλ‘ νμ κ³Ό μ€νΌλ μ΄μ μ μ΄λ¦μ λΆμ¬νλ€.
- κ°μ₯ μΆμμ μΈ μ΄λ¦μ λΆμΈλ€. Tip: λ§€μ° λ€λ₯Έ λλ² μ§Έ ꡬνμ μμνλ€. κ·Έλ¦¬κ³ , ν΄λΉ λ©μλμ λμΌν μ΄λ¦μ λΆμΈλ€κ³ μμνλ€. κ°μ₯ μΆμμ μΈ μ΄λ¦μ λ©μλμ λΆμ΄κ² λ κ²μ΄λ€.
μ’μ μ:
public class TicketSeller {
private var ticketOffice: TicketOffice
func sell(to audience: Audience) {
audience.buyTicket(from:ticketOffice.ticket)
}
}
public class PeriodCondition {
func isSatisfied(_ screening: Screening) { ... }
}
λμ μ:
public class TicketSeller {
private var ticketOffice: TicketOffice
func setTicket(to audience: Audience) {
audience.setTicket(from:ticketOffice.ticket)
}
}
public class PeriodCondition {
func isSatisfiedByPeriod(_ screening: Screening) { ... }
}
μ΄λ€ μ€νΌλ μ΄μ λ λͺ λ Ήμ΄ λμμ μΏΌλ¦¬κ° λκ² νμ§ μλλ€.
루ν΄
μ μ΄λ€ μ μ°¨λ₯Ό λ¬Άμ΄ νΈμΆ κ°λ₯νλλ‘ μ΄λ¦μ λΆμ¬ν κΈ°λ₯λͺ¨λμ΄λ€.루ν΄
μνλ‘μμ
μν¨μ
λ‘ λλλ€.νλ‘μμ
λ μ¬μ΄λμ΄ννΈλ₯Ό λ°μμν¬ μ μμ§λ§ κ°μ λ°νν μ μλ€.ν¨μ
λ μ¬μ΄λμ΄ννΈλ₯Ό λ°μμν¬ μ μμ§λ§ κ°μ λ°νν μ μλ€. λͺ λ Ή : 쿼리 =νλ‘μμ
:ν¨μ
- λΆλ¦¬λ‘ μΈν κΈμ μ μΈ ν¨κ³Ό
- 쿼리μ μμλ₯Ό μμ λ‘κ² λ³κ²½ν μ μλ€.
- κ°μ²΄μ§ν₯ ν¨λ¬λ€μμ κ°μ²΄μ μνλ³νλΌλ μ¬μ΄λμ΄ννΈλ₯Ό κΈ°λ°μΌλ‘ νκ³ μλ€. λͺ λ Ήκ³Ό 쿼리λ₯Ό λΆλ¦¬νλ©΄ κ°μ²΄μ μ¬μ΄λμ΄ννΈλ₯Ό μ μ΄νκΈ°κ° μμν΄μ§λ€.
- κ°λ μ±μ΄ μ’μμ§κ³ , λλ²κΉ μ΄ μ½κ³ , μ€ν κ²°κ³Όλ₯Ό μμΈ‘ κ°λ₯νλ€.
ν¨μν νλ‘κ·Έλλ°μ μ¬μ΄λμ΄ννΈκ° μ‘΄μ¬νμ§ μλ μνμ μΈ ν¨μλ₯Ό κΈ°λ°μΌλ‘ νλ€. κ·Έλμ, μ€νκ²°κ³Όλ₯Ό μ΄ν΄νκ³ μμΈ‘νκΈ°κ° λ μ½λ€.
struct
λ value semanticsλ₯Ό κ°μ§κ³ μλ€. μ 체μ±(identity)μ΄ μλ κ²μλ struct
λ₯Ό μ¬μ©νλ€. [a, b, c]
λ₯Ό ν¬ν¨νλ λ°°μ΄μ [a, b, c]
λ₯Ό ν¬ν¨νλ λ€λ₯Έ λ°°μ΄κ³Ό μ€μ λ‘ λμΌνλ©° μμ ν κ΅νν μ μλ€. 첫 λ²μ§Έ λ°°μ΄μ μ¬μ©νλ λ λ²μ§Έ λ°°μ΄μ μ¬μ©νλ μκ΄μλ€. μλνλ©΄ κ·Έκ²λ€μ μ νν κ°μ κ²μ λνλ΄κΈ° λλ¬Έμ΄λ€. κ·Έλ κΈ° λλ¬Έμ λ°°μ΄μ struct
μ΄λ€.
class
λ reference semanticsλ₯Ό κ°μ§κ³ μλ€. μ 체μ±(identity)μ΄λ νΉμ ν λΌμ΄ν μ¬μ΄ν΄μ΄ μλ κ²μ λν΄ class
λ₯Ό μ΄μ©νλ€. λ μ¬λ κ°μ²΄λ μλ‘ λ€λ₯΄κΈ° λλ¬Έμ μ¬λμ class
λ‘ λͺ¨νν ν κ²μ΄λ€. λ μ¬λμ΄ μ΄λ¦κ³Ό μλ
μμΌμ΄ κ°λ€κ³ ν΄μ κ°μ μ¬λμ΄ λλ κ²μ μλλ€. κ·Έλ¬λ 1950λ
3μ 3μΌμ λ μ§λ 1950λ
3μ 3μΌμ λ€λ₯Έ λ μ§ κ°μ²΄μ κ°κΈ° λλ¬Έμ κ·Έ μ¬λμ μλ
μμΌμ structκ° λ κ²μ΄λ€. λ μ§ μ체λ μ 체μ±μ΄ μλ€.
νμΌμ λ Όλ¦¬ κ·Έλ£ΉμΌλ‘ λλκΈ° μν΄ λμ΄κ° λ€λ₯Έ λΉ μ€λ³΄λ€λ μ΄λ¬ν ν¬λ§·ν κ°μ΄λλΌμΈμ μ νΈνλ€.
extension
μ μ¬μ©νμ¬ μ½λλ₯Ό λ
Όλ¦¬μ μΈ κΈ°λ₯ blockμΌλ‘ λλμ΄μ§λλ‘ κ΅¬μ±νλ€.
κ° extension
μ // MARK: -
μ£Όμμ λ¬μ μ μ 리ν΄μΌ νλ€.
κ΄λ ¨ λ©μλκ° νλ‘ν μ½κ³Ό ν¨κ» κ·Έλ£Ήνλμ΄ μ μ§λλ©° κ΄λ ¨ λ©μλλ₯Ό μ°ΎκΈ°κ° λ μ½κ³ μ μ§λ³΄μκ° μ©μ΄νλ€.
μ’μ μ:
class MyViewController: UIViewController {
// class stuff here
}
// MARK: - UITableViewDataSource
extension MyViewController: UITableViewDataSource {
// table view data source methods
}
// MARK: - UIScrollViewDelegate
extension MyViewController: UIScrollViewDelegate {
// scroll view delegate methods
}
λμ μ:
class MyViewController: UIViewController, UITableViewDataSource, UIScrollViewDelegate {
// all methods
}
λ΄μ₯ λͺ¨λμ λ¨Όμ λκ³ , λΉ μ€λ‘ μΈμ»¨λνν°λ₯Ό ꡬλΆνλ€. μ΄ν μΆκ° λΉ μ€λ‘ μλνν°λ₯Ό ꡬλΆν μ μλ€. header comment λ€μμ ν μ€μ λμ°κ³ 첫 import λ¬Έμ μμνλ€. μ΄μΈμλ import λ¬Έ μ¬μ΄μ λΉ μ€μ μΆκ°νμ§ μλλ€.
standard organization λ°©λ²μ ν΅ν΄ νμΌμ΄ μ΄λ€ λͺ¨λμ μμ‘΄νλμ§λ₯Ό λ³΄λ€ μ μνκ² μμλΌ μ μλ€.
μ’μ μ:
// Copyright Β© 2022 Wantedlab. All rights reserved.
//
import UIKit
import SecondParty
import SnapKit
import React
import Toaster
μμΈ: @testable
μ μΌλ°μ μΈ import
λ¬Έ λ€μ μμΉνκ³ λΉ μ€λ‘ ꡬλΆν΄μΌ νλ€.
μ’μ μ:
// Copyright Β© 2022 Wantedlab. All rights reserved.
//
import Nimble
import Quick
@testable import wanted
λμ μ:
// Copyright Β© 2022 Wantedlab. All rights reserved.
//
import Nimble
@testable import wanted
import Quick
+
λ 짧μ§λ§ λͺ
ννκ² μλ―Έλ₯Ό μ λ¬νλ€. νμ₯λλ μ½λλ₯Ό λ
Όλ¦¬μ μΈ κΈ°λ₯ blockμΌλ‘ λλ μ μμΌλ©°, κ°λ
μ±κ³Ό μ μ§λ³΄μμ±μ΄ μ’μμ§λ€. μ°Ύλ νλͺ©μ λν κ²μ λ²μλ₯Ό μ’νλ λ° λμμ΄ λλ€.
μ’μ μ:
```swift
AppDelegate+.swift
UIColor+.swift
UIImage+.swift
UIViewController+.swift
```
The Official raywenderlich.com Swift Style Guide
μ€λΈμ νΈ by μ‘°μνΈ