Chapter1. The Architecture of Swift

캣코타·2022년 3월 9일
0
post-thumbnail

들어가기전

  • : application의 줄임말
  • “” 내부의 글들은 모두 O’Relly 챕터1 내용을 인용한 것이다.

Chapter1 주제 : 스위프트의 전체적인 아키텍쳐와 환경(nature)에 대하여

Ground Being

  • 스위프트에선 명령(command)을 statement(문)로 한다.
  • 하나의 statement는 하나의 line으로 이루어진다.
    	//예시
       print("hello")
  • 두개 이상의 statement를 하나의 line에 작성하기 원하는 경우 세미콜론(;)
  • 스위프트는 compiled language이다.
    • build하기 이전에 컴파일러가 컴퓨터가 이해가능한 언어(low-level)로 바꾼 후 error가 없어야 실행(run) 가능한 언어

Everything is object

  • 스위프트에선 모든것은 object라는 말이 있다. 이것을 어떻게 해석할 수 있을까?

  • 이 문장의 의미를 이해하려면 object와 everything가 무엇인지 먼저 생각해 보아야한다.

  • 저자는 object를 메세지를 전달받을 수 있는 것을 의미한다고 정의한다.

    • object : 명사, 확장 및 변경 할 수 있는 모든 것

      • “ In Swift, every noun is an object, and every verb is a message. ...
        the ultimate acid test for whether something is an object in Swift is whether you can modify it"

      • 여기서 메세지를 전달하는 방법을 dot notation 라고 함

        class Mesenger {
        	var name: String = "mesenger"
        
        	func deliver() {
        		print("배달왔으요~")
        	}
        }
        
        let mesenger = Mesenger()
        
        //MARK: Mesenger타입 인스턴스(object)에게 메세지 보내기
        mesenger.name
        mesneger.deliver
        
    • message : 필수적인 instruction

      • “ A message, roughly speaking, is an imperative instruction. ”

  • 그렇다면 everything의 의미는 어떻게 정의할 수 있을까?

    • 저자는 원시적인(primitive) 언어적 엔터티(entity)또한 메세지를 보낼 수 있는 object가 된다는 것을 의미한다고 한다.

      • "The idea of everything being an object is a way of suggesting that even “primitive” linguistic entities can be sent messages."
    • 원시적인 언어적 엔터티(primitive languistic entites) : 엔터티는 최소단위를 의미. 언어에서 제공하는 가장 기본적인 것의 최소단위라고 이해하면 되지 않을까?

      • 사실 언어적 최소단위도 class, struct, enum과 같은 타입으로 구현한 것이기 때문에 원시적인 언어적 엔터티라는 것은 결국 이런 구체타입(혹은 타입의 인스턴스)을 의미하는 듯 하다.
  • 예시 코드

    	//스위프트에선 정수타입을 scalar 데이터로 이용할 수 있을 뿐 아니라 객체로서 메세지를 보낼수도 있음 
          let sum = 1 + 2
          let explain = 1.description
    • 1(Int 타입)을 예시로 들었을까?
      • 다른언어에선 1과 같은 숫자, 즉 이미 언어에 내장되어 있는 primitive(or scalar) 데이터 타입의 경우 object로 생각하지 않는다.
      • 파이썬의 경우 1.decription 같이 타입자체에 메세지를 보낼 수 없음. 단지 수단으로서 사용될 뿐

everyting is object 의 의미
스위프트의 모든 타입은 궁극적으론 객체가 될 수 있다.(= 메세지를 주고 받을 수 있다)
정수타입, 객체타입이 나눠지는 Objective-c와는 다르다

++ Swif API GuideLines에선 Int를 어떻게 설명하고 있을까?

  • Int
    • A signed integer value type.
      On 32-bit platforms, Int is the same size as Int32, and on 64-bit platforms, Int is the same size as Int64.
    1. initializer
      • NSNuber를 Int 타입으로 바꾸도록 하는 것
        흥미로운 점은 주어진 정수에 가장 가까운 수로 clamping하는 이니셜라이저가 있다는 점
        (init(clamping: Other))
      • Float, Double등의 타입도 받을 수 있음
      • ASCII 이름도 받아서 인스턴스 생성가능
    2. method
      • negate() : 마이너스로 바꿔주는 메소드.

Three Flavors of Object Type

  • 위에서 말한 object 가 될 수 있는 타입을 Object-C와 비교하여 설명하고 있다.
  • class, enum, struct를 Object가 될 수 있는 type이라고 한다.
    • Object-C에선 class(혹은 class 인스턴스)만 object 가 될 수 있는것과 굉장히 다르다 (Object-C에선 enum, struct는 메세지를 못 받는듯하다. )

기본용어 정리 - variable, declare, statement

  1. variable : object의 이름.

    • object가 담긴 신발상자
    • object의 reference
    • 초기화(initialization)을 통해 declaration이 된다. declare하기 전까진 variable은 존재하지 않는다.
    • declare 와 initialization의 구분
      struct Person {
      	//declaration은 했지만 initialization하지 않은 상태 
      	var name: String
      }
      
      //선언과 동시에 초기화 
      let number = 1
    • swift programming language에선 variable을 무엇이라고 하고있나
      = 값을 가진 특정 타입의 이름과 연관된(associate)것.
      • Constants and variables associate a name (such as maximumNumberOfLoginAttempts or welcomeMessage) with a value of a particular type (such as the number 10 or the string "Hello")
      • variable에 값을 할당하기 위해선 할당연산자(=)를 사용한다.
        	 let number = 1
  2. declare : let이나 var를 쓰는 것. 즉 내가 변수를 만들겠다고 표시하는 것. 신발상자(let, var)를 주고 신발을(객체) 여기다 담으라고 하는 것

    • variable = a
    • variable : let, var + name
    • 스위트에선 선언(declaration )은 종종 초기화와 함께 진행된다.

      In Swift, declaration is usually accompanied by initialization — you use an equal sign to give the variable a value immediately, as part of the declaration.

      • 초기화 : 메모리에 자리 만들어 주는 것
  3. statement

let one = 1
var two = 2
two = one
  • 현재 총 3개의 statement 가 있다.
    • satement의 왼쪽을 assignment 라고 한다
      • 메모리 관점에서 보면 1이나 2에게 자리를 만들어주는 것이기 때문에
    • = : assignment operator

      Get the value of what’s on the right side of me, and use it to replace the value of what’s on the left side of me.

Functions

"A function is a batch of code that can be told, as a batch, to run."

  • 함수를 만드는 것 까진 좋다. 실행해야하는 코드의 집합체이니. 그럼 이 함수를 시작하게 하는 것은 누구인가?

    • 컴파일언어이기 때문에 runtime에 어떤 메소드 실행할 지 정해진다.
      main() 함수가 맨 처음 launch시작

The Structure of a Swift File

top level : 최상단 스코프와 그 다음 스코프 사이의 공간

  • top level의 간단한 예시
  //현재 main.swift 파일이라고 가정
이 공간이 top level
  
  
 //또다른 스코프가 생김 
	{ 
  
  
	}
  • 스위프트 파일의 top level에 존재할 수 있는 4가지를 설명하고 있다.
  1. Module import statements
    1. 모듈은 파일보다 높은 레벨의 유닛

    2. 모듈은 import 를 통해 서로를 인식할 수 있며 각각의 모듈은 여러개의 파일들로 이루어진다.

      = 이것이 iOS program에서 Cocoa 기반의(?) 프레임워크와 소통하는 방식.

      “That is how you are able to talk to Cocoa in an iOS program: the first line of your file says import UIKit.”

    3. 파일끼리는 서로 인식하지 못한다.

  2. Variable delarations
    1. top level에서의 선언은 global varaible

  3. Function declarations
    • Executable code 는 함수 바디 내부에서만 선언가능하다.
      • "A statement like one = two or print("hello") is executable code"
      • "Executable code generally refers to machine language, which is the set of native instructions the computer carries out in hardware."
    • main.swift
      - executable code를 top level에서 선언할 수 있음
      - main.swift 파일을 제외하곤 top level에서 executable code 선언 불가

  4. Object type declarations
//1. 모듈  
import Foundation

//2. 
let swift = "Swift"

//3.
func saySwift() {
	print("Swift")
}

//4.
class ObjectType {
...
}

Scope and Lifetime

  1. scope : ability to be seen by other things
  • things들은 같은 레벨 혹은 높은 레벨의 것들만 인식할 수 있다.

    • 파일이 자신보다 높은 레벨인 모듈은 알 수 없지만 모듈은 자기가 가지고 있는 파일에 대해 알고 있는 것 처럼
  • scope가 중요한 이유 : 정보를 공유하는 방법으로서 매우 중요.
    (정보공유자의 범위와 한계를 정할 수 있다는 것에 의의를 둔 듯하다)

  • 예시
    : if 구문 내부가 fool 함수보다 더 낮은 레벨. 따라서 if구문 내부의 것들은 if 구문 밖의 것들을 인식할 수 있지만, if 구문 밖의 것들은 if 내부의 객체들에 대해 접근할 수 없다.

    func fool() {
    	if true {
    		class Idiot {} 
    		var one = 1
    		one = one + 1
    	}
    }
  • life time = 메모리에 살아있는 기간
    • global, local에 따라 메모리에 살아남아있는 기간이 다름

Object members

  • 세개의 객체타입(class, struct, enum) 내부의 top level에서 선언하는 것들을 설명하고 있다.
    • 객체 내부에서 top 레벨로 선언하는 변수 = property

    • 객체 내부에서 top 레벨에 선언하는 함수 = method

      ⇒ property와 method로 객체간의 메세지를 보낸다.

NameSpaces

  • “A namespace is a named region of a program. ”
    • named region(이름붙여진 지역)이란 것은 결국 스코프 내부를 의미하는게 아닐까?
      ( 스코프는 {}와 모듈로 구분된다)
  • 네임스페이스의 name으로 객체 내부의 속성, 메소드에 접근한다
    • 이름 자체로는 안전성, privacy를 지키지 못한다. 즉 내부 member로 그걸 구현해야함(private, internal등등)
  • EX) Happy가 네임스페이스.
    • Day에 접근하려면 Happy.Day 로 접근해야한다. 이유 : 같은 레벨, 혹은 높을 레벨에서만 접근가능(scope내에 있어야한다)
      class Happy {
      	class Day {} 
      }

Modules

  • “The top-level namespaces are modules.”
    가장 최상단의 namespaces를 모듈이라고 한다.
    - 네임스페이스는 간단히 말하자면 오브젝트 타입, 변수(상수) 등의 이름이라고 할 수 있는데 모듈은 이것들을 참조할 수 있도록 하는 가장 최상단의 이름

        ex) 토스앱의 경우 토스 내부의 Bill이라는 타입에 접근하고 싶을 때 Toss.Bill 로 접근 가능 
        
    - Xcode 실행 시 우리는 기본적으로  `Swift` 라는 모듈내에서 시작하는 것
        
        
  • 우리가 만드는 app도 하나의 모듈이자 namespace.(앱의 이름 자체가 namespace)

    “If my app is called MyApp, then if I declare a class Manny at the top level of a file, that class’s real name is MyApp.Manny. But I don’t usually need to use that real name, because my code is already inside the same namespace, and can see the name Manny directly.”

  • 앱도 하나의 모듈, Swift, Cocoa's Foundation framwork(Foundation, UIKit) 등도 모두 모듈.

    → 만약 이 모듈 내의 객체에 접근하고 싶다면, Foundation.NSString 과 같이 접근해야 할 것.

    • Swift 모듈은 항상 implicitly하게 import되고 있음 → 굳이 맨 위에 선언하지 않아도 되는 이유
      • print 같은 메소드들은 Swift 모듈내에서 정의된 함수이기 때문에 NameSpace를 따로 명시하지 않아도 사용 가능했던 것 (Swift.print("hello") 와 같이 작성해도 되지만 의미없음)
  • 그렇다면 아래와 같이 import하는 것의 의미는 무엇일까?

    import UIKit
    import Foundation

    = UIKit, Foudnation 프레임워크를 같은 레벨의 scope로 만들겠다.
    = 접근할 수 있게 됨
    → NSString 등이 위치한 scope의 NameSpace를 앞에 명시하지 않아도 사용할 수 있는 이유(ex : Foundation.NSString)

  • 만약 모듈내의 객체(?)와 같은 이름의 것을 구현한다면 NameSpace를 통해 접근해야함

    String이라는 이름의 타입을 Swift 모듈 내에서 구현하는 경우 기존 String 객체에는 Swift.String으로 접근
    ( 바로 String으로 접근가능하지만 구분이 어려울 수 있음)

    //example.swift 파일 내부라고 가정 
    
    struct String {
        let test = "asdf"
    }
    • String타입을 사용하려고 하면 컴파일러가 Swift 모듈내에서 의미 정의된 구조체 타입의 String과(상단) 다른 파일에서 동일한 이름으로 정의한 String 타입을 동시에 보여준다.
  • swift programming language 에서는 모듈과 소스파일에 대해 어떻게 말하고 있나?

    요약
    모듈과 소스파일은 스위프트의 접근제어모델의 기반이된다.
    소스파일은 모듈내에 위치하며 모듈은 모듈을 import 할 수 있다. 모듈은 보통 프레임워크, 어플리케이션(application)을 의미한다.

    • 그럼 접근제어모델의 기반이 된다는 것은 어떤의미인가?
      앱을 빌드할 때 app bundle 과 framework와 같은 빌드 타겟들은 각각의 모듈로 취급된다. 따라서 각각의 모듈 내부의 타입(혹은 그 외의 것)을 참조하기 위해선 import를 해야한다.

Instances

“Object types — class, struct, and enum — have an important feature in common: they can be instantiated. In effect, when you declare an object type, you are only defining a type. To instantiate a type is to make a thing — an instance — of that type.”

“In Swift, instances can be created by using the object type’s name as a function name and calling the function. ”

  • 인스턴스를 만들면 instance message 를 전달 할 수 있다.

Why Instance?

“Instacne is both code and data. ... The instance has, at every moment, a state — the complete collection of its own personal property values. An instance is a device for maintaining state. It’s a box for storage of data.”

  • 인스턴스는 코드이자 데이터이다. 타입의 코드를 인스턴스들끼리 공유하지만 내부의 데이터(각각의 속성 값)는 인스턴스마다 다르게 가지고 있다. 즉 각각의 인스턴스로 state 를 나타내며 그 값을 유지하는 device로서 역할한다.

    ⇒ OOP 의 power 가 드러나는 부분

  • 왜 인스턴스를 만드는가?

    • 타입자체도 객체이고 메세지를 전달할 수 있다.(아래의 예시처럼) 그렇다면 왜 인스턴스를 만들어야 할까?

      class Manny {
      	class Klass {
      		var name = "Klass"			
      	}
      }
      
      Manny.Klass.name 
      //이렇게 접근 가능 

→ 이유 : 각각의 인스턴스마다 내부의 property 를 다르게 정의할 수 있고 객체끼리 구분할 수 있기 때문

  • 타입 내부에 선언된 코드가 다른 인스턴스들과 공유되고 있어도(동일해도) 데이터는 각각의 인스턴스에 속해있다.
    > **“In short, an instance is both code and data.** The `code` it gets from its type and in a sense is shared with all other instances of that type, but the `data` belong to it alone. The data can persist as long as the instance persists. ”
    > 

self = 자기 자신에게 메세지 보내고 싶을 때

  • 인스턴스도 object! 따라서 자기 자신에게도 메세지를 보내야 할 때가 있음. 이럴 때 사용하는 키워드가 self

    When an instance’s code says self, it is referring to this instance

  • self 를 명시하지 않아도 되긴하는데 왠만하면 써라. 그래야 코드읽기 편하다

Privacy

  • 접근제어자 키워드 붙여라

Design

  • 인스턴스들은 주로 variable에 할당된다 → 인스턴스의 life time은 변수들이 해당 인스턴스를 refer 할 때까지 → 그렇다면 내가 작성하는 코드들의 인스턴스들은 app에 대해 어떻게 refer 를 얻게 되는 것인가

    “Before you write a single line of code, the framework ensures that your app, as it launches, is given some instances that will persist for the lifetime of the app, providing the basis of your app’s visible interface and giving you an initial place to put your own instances and give them sufficiently long lifetimes.”

⇒ 애플이 제공하는 framework가 application 런치하기 전 앱의 life-time 을 지속할 수 있는 인스턴스를 제공한다

  • 앱이 시작되는 main() 함수는 Xcode가 제공하지만 그것을 호출하는 것은 시스템이다.
    • The Xcode-provided main function calls UIKit's UIApplicationMain(_*:*_:_*:*_:) function.
      (문서링크)

⇒ 그렇다면 우린 무엇을 디자인 해야하는가? 비지니스 로직

“What the framework cannot tell you is how to design the underlying business logic of whatever your app does behind the scenes. ”
오브젝트타입, 기능성 그리고 그 관계들을 적절한 구조로 설계하는 것

profile
to be iOS Developer

0개의 댓글