Swift 계급 - 일반 형

8114 단어
범용 인 코딩 의 목적
표현 알고리즘 이나 데이터 구조 가 요구 하 는 핵심 인터페이스.(핵심 인 터 페 이 스 는 무엇 일 까? 즉, 실현 하고 자 하 는 기능 의 최소 수 요 를 찾 는 것 이다.)
일반적인 인 코딩 이 가 져 온 장점:
1. 다시 사용 할 수 있 는 함수 와 데이터 구 조 를 쓸 수 있 습 니 다. 예 를 들 어 Array, Set...
2. 일반적인 방법 을 만 들 수 있 습 니 다. 예 를 들 어 func idenity < A > (input: A) - > A
오늘 의 연구 내용:
1. 범용 코드 를 어떻게 쓰 는가
2. 컴 파일 러 가 일반적인 코드 를 어떻게 처리 하 는 지 이야기 합 니 다.
3. 우리 의 일반적인 코드 를 어떻게 최적화 합 니까?
무 거 운 짐
4. 567917. 무 거 운 짐 은 무엇 입 니까?다시 불 러 오 는 것 은 같은 이름 을 가지 고 있 지만 매개 변수 나 되 돌아 오 는 유형 이 다른 여러 가지 방법 을 서로 다시 불 러 오 는 방법 이 라 고 합 니 다
func log(_ view: UIView) {
  print("It's a \(type(of: view)), frame: \(view.frame)")

}
func log(_ view:UILabel){ let text = view.text ?? "empty" print("It's a label,text:(text)") }

-       swift                 ?

          ,                  。    

  ```
let label = UILabel(frame: CGRect(x: 20, y: 20, width: 200, height: 32))
label.text = "password"
log(label)//It's a label,text:password

let button = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
log(button)//It's a UIButton, frame: (0.0, 0.0, 100.0, 50.0)

4. 567917. 주의해 야 할 것 은 1. 재 부팅 의 사용 은 컴 파일 기간 에 정적 으로 결정 되 고 컴 파일 러 는 변수의 정적 유형 에 따라 재 부팅 을 결정 합 니 다. 실행 할 때 값 의 동적 유형 에 따라 결정 되 는 것 이 아 닙 니 다.2. 그러나 조작 자 를 사용 하여 다시 불 러 올 때 컴 파일 러 는 이상 한 행동 을 나타 낸다. 유형 검사 기 는 일반적인 버 전 을 고려 하지 않 고 일반적인 버 전 을 사용 할 것 이다
precedencegroup ExponentiationPrecedence {
  associativity:left
  higherThan:MultiplicationPrecedence
}
infix operator **: ExponentiationPrecedence

func **(lhs: Double, rhs: Double) -> Double {
    return pow(lhs, rhs)
}
func **(lhs: Float, rhs: Float) -> Float {
    return powf(lhs, rhs)
}

/ / 정수 에 대한 재 부팅 func * * (lhs: I, rhs: I) - > I {/ / 를 IntMax 로 변환 하고 Double 의 재 부팅 계산 결 과 를 사용 합 니 다. / / 그리고 numericCast 로 원래 유형 let result = Double (lhs. toIntMax () * * Double (rhs. toIntMax () return numericCast (IntMax (result)} func * * (lhs: I, rhs: I) - > I {let result = Double (lhs. toIntMax () * Double(rhs.toIntMax()) return numericCast(IntMax(result)) }
         2**3,   :


Playground 실행 실패: error: 범 형. playground: 75: 2: error: ambiguous use of operator '23 ^
범 형. playground: 58: 6: note: found this candidate func * * (lhs: Double, rhs: Double) - > Double {^
범 형. playground: 61: 6: note: found this candidate func * * (lhs: Float, rhs: Float) - > Float {^
            ,            ,2 3       Double   Float,                       ,             Double     Float   。

    :
1、                 (let intResult = Int(2)**3)

2、          (let intResult:Int = 2**3)

####          
   
####          
                  ,              ,        。

-                  :

           ,      User    (    ,        ,      ,            )
  
  ```
  //         
  func loadUsers(callback: ([User]?) -> ()) {
  
      let usersURL = webserviceURL.appendingPathComponent("/users")
      let data = try? Data(contentsOf: usersURL)
      let json = data.flatMap {
          try? JSONSerialization.jsonObject(with: $0, options: [])
      }
      let users = (json as? [Any]).flatMap { jsonObject in
          jsonObject.flatMap(User.init)
      }   
      callback(users)
  }

  ```
                       ,            :
  
  ```
  //         
  func loadBlogPosts(callback: ([BlogPost]?) -> ()) { 
      let blogpostURL = webserviceURL.appendingPathComponent("/blogposts")
      let data = try? Data(contentsOf: blogpostURL)
      let json = data.flatMap {
          try? JSONSerialization.jsonObject(with: $0, options: [])
      }
      let blogposts = (json as? [Any]).flatMap { jsonObject in
          jsonObject.flatMap(BlogPost.init)
      }
      callback(blogposts)
  }

  ```
  
    :
  
  1、    
  
  2、            
  
      :      

-       (      )

  ```
  func loadResource(at path: String,parse: (Any) -> A?,callback: (A?) -> ()){
let resourceURL = webserviceURL.appendingPathComponent(path)
let data = try? Data(contentsOf: resourceURL)
let json = data.flatMap {
try? JSONSerialization.jsonObject(with: $0, options: [])
}
callback(json.flatMap(parse))
}
```
위의 두 함 수 는 loadResource 재 작성 을 기반 으로 합 니 다.
```
func loadUsers(callback: ([User]?) -> ()) {
loadResource(at: "/users", parse: jsonArray(User.init), callback: callback)
}
func loadBlogPosts(callback: ([BlogPost]?) -> ()) {
loadResource(at: "/blogposts",
parse: jsonArray(BlogPost.init),
callback:callback)
}
func jsonArray(_ transfrom:@escaping (Any)  -> A?) -> (Any) -> [A]? {
return { array in
guard let array = array as? [Any] else {
return nil
}
return array.flatMap(transfrom)
}
}
```
단점: loadResource 함수 에서 path 와 parse 의 결합 이 매우 긴밀 합 니 다. 그 중 하 나 를 바 꾸 면 다른 하 나 를 바 꿔 야 할 수도 있 습 니 다.
솔 루 션: 일반적인 데이터 형식 만 들 기
- 범용 데이터 형식 만 들 기
```
struct Resource{
let path:String
let parse:(Any) -> A?
}
extension Resource {
func loadSynchronously(callback: (A?) -> ()) {
let resourceURL = webserviceURL.appendingPathComponent(path)
let data = try? Data(contentsOf: resourceURL)
let json = data.flatMap {
try? JSONSerialization.jsonObject(with: $0, options: [])
}
callback(json.flatMap(parse))
}
}
let usersResource: Resource =
Resource(path: "/users", parse: jsonArray(User.init))
let postsResource: Resource =
Resource(path: "/posts", parse: jsonArray(BlogPost.init))
```
장점: 새로운 자원 을 추가 하기 쉬 우 며 새로운 함 수 를 만 들 필요 가 없습니다.
- 비동기 처리 방법 추가
기 존의 api 접속 점 을 설명 하 는 코드 를 바 꿀 필요 가 없습니다.
```
extension Resource {
func loadAsynchronously(callback: @escaping (A?) -> ()) {
let resourceURL = webserviceURL.appendingPathComponent(path)
let session = URLSession.shared
session.dataTask(with: resourceURL) { data, response, error in
let json = data.flatMap {
try? JSONSerialization.jsonObject(with: $0, options: [])
}
callback(json.flatMap(self.parse))
}.resume()
}
}
```
\ # \ # \ # 일반적인 작업 방식 (컴 파일 러 의 시각 에서 볼 때)
- 표준 라 이브 러 리 안의 min 함수
```
func min(_ x: T, _ y: T) -> T {
return y < x ? y : x
}
```
이 함수 에 대해 컴 파일 러 는 두 가지 관건 적 인 정보 가 부족 하 다.
1. 컴 파 일 러 는 T 형식의 변수의 크기 를 모른다.
2. 컴 파 일 러 는 호출 해 야 할 < 함수 에 과부하 가 있 는 지 모 르 기 때문에 호출 해 야 할 함수 의 주소 도 모른다.
이 두 가지 관건 적 인 정보 가 부족 하기 때문에 이 함수 에 직접 코드 를 만 들 지 않 습 니 다.
- 이 문제 들 을 어떻게 해결 할 것 인가.
컴 파일 러 가 일반적인 형식의 값 을 만 났 을 때 고정 크기 의 용기 구역 저장 자 에 게 포장 합 니 다. 이 값 이 용기 의 사 이 즈 를 초과 하면 swift 는 더미 위 에 메모 리 를 신청 하고 이 값 의 인용 을 용기 에 저장 합 니 다.그 밖 에 모든 범 형 유형의 매개 변수 에 대해 컴 파일 러 는 하나 이상 의 목격 표를 유지 하 는데 그 중에서 하나의 값 목격 표 와 유형 적 으로 모든 협의 가 하 나 를 제약 하 는 협의 목격 표를 포함한다.이 목격 표 들 은 실행 중인 함 수 를 동적 으로 호출 하여 정확 한 실현 에 보 내 는 데 사 용 될 것 이다.
우리 가 방금 묘사 한 '컴 파일 한 번, 동적 배포' 모델 은 swift 팬 시스템 의 중요 한 디자인 목표 이다. 그러나 이런 방법 은 단점 이 있다. 운행 할 때 성능 이 비교적 낮 고 하나의 함수 호출 에 있어 이런 비용 은 무시 할 수 있 지만 범 형 은 swift 에서 매우 보급 되 기 때문에 이런 비용 은 쉽게 쌓 여서 성능 문 제 를 일 으 킬 수 있다.그럼 어떻게 하면 이 추가 비용 을 피 할 수 있 습 니까?
\ # \ # \ # # 범 형 특 화
- 팬 특 화 는 무엇 인가.
범 형 특 화 는 컴 파일 러 가 구체 적 인 매개 변수 유형, 예 를 들 어 (Int) 에 따라 min 과 같은 범 형 유형 이나 함 수 를 복사 하 는 것 을 말한다. 특 화 된 함 수 는 Int 에 대해 최적화 시 켜 모든 추가 비용 (주로 동적 으로 파 견 된 비용) 을 제거 할 수 있다.범 형 특 화 는 컴 파일 기간 에 최적화 기 에 의 해 이 루어 진다.
코드 에서 자주 Int 를 사용 하여 min 함 수 를 호출 하고 Float 버 전 을 한 번 만 호출 하면 Int 버 전 만 특 화 될 수 있 습 니 다. min 은 Int 에 대한 특 화 버 전 은 다음 과 같 습 니 다.
```
func min(_ x: Int, _ y: Int) -> Int {
return y < x ? y : x
}
```
범 형 은 비용 을 줄 일 수 있 지만 한계 가 있다. 범 형 특 화 는 컴 파일 러 에서 범 형 유형의 모든 정의 와 특 화 를 하고 싶 은 유형 을 볼 수 있 을 때 만 유효 하 다.범 형 코드 와 범 형 코드 를 같은 파일 에 정의 할 때 만 범 형 특 화 를 할 수 있다 는 얘 기다.
만약 우리 가 범 형 특 화 를 원한 다 면 모듈 경 계 를 넘 어 사용 할 수 있다 면 어떻게 합 니까?swift 에 반공 식 태그 가 있 습 니 다 @specialie, 일반 코드 를 지정 한 버 전의 특 화 를 통 해 다른 모듈 에서 도 사용 할 수 있 습 니 다.
```
@_specialize(Int)
@_specialize(String)
public func min(_ x: T, _ y: T) -> T {
return y < x ? y : x
}
```
주의해 야 할 것 은: 우 리 는 Public 를 추 가 했 습 니 다. internal, fileprivate, private api 가 @ 를 추 가 했 기 때 문 입 니 다.specialie 는 무의미 하 다.다른 모듈 에 보이 지 않 기 때문이다.
\ # \ # \ # \ # 참고 자료: Swift 진급

좋은 웹페이지 즐겨찾기