Lớp cơ sở gốc Swift hoặc NSObject


105

Tôi đã thử nghiệm một số isa swizzing với Swift và thấy rằng nó chỉ hoạt động khi NSObject là một siêu cấp (trực tiếp hoặc cao hơn) hoặc bằng cách sử dụng trang trí '@objc'. Nếu không, nó sẽ tuân theo kiểu điều phối tĩnh và vtable-như C ++.

Có bình thường để xác định một lớp Swift không có lớp cơ sở Cocoa / NSObject không? Nếu tôi lo ngại, điều này có nghĩa là đã đề cập nhiều đến tính năng động của Objective-C, chẳng hạn như phương pháp đánh chặn và xem xét nội tâm trong thời gian chạy.

Hành vi thời gian chạy động là trọng tâm của các tính năng như quan sát thuộc tính, Dữ liệu cốt lõi, Lập trình hướng theo khía cạnh , Nhắn tin thứ tự cao hơn , khung phân tích & ghi nhật ký, v.v.

Sử dụng kiểu gọi phương thức của Objective-C thêm khoảng 20 toán hạng mã máy vào một lệnh gọi phương thức, vì vậy trong một số tình huống nhất định ( nhiều lệnh gọi chặt chẽ đến các phương thức có phần thân nhỏ ) C ++ kiểu tĩnh và vtable có thể hoạt động tốt hơn.

Nhưng với quy tắc chung 95-5 ( 95% hiệu suất tăng đến từ việc điều chỉnh 5% mã ), không hợp lý khi bắt đầu với các tính năng động mạnh mẽ và tăng cường ở những nơi cần thiết?


Liên quan: Swift có hỗ trợ lập trình hướng khía cạnh không? stackoverflow.com/a/24137487/404201
Jasper Blues

Câu trả lời:


109

Các lớp Swift là lớp con của NSObject:

  • chính là các lớp Objective-C
  • sử dụng objc_msgSend()cho các cuộc gọi đến (hầu hết) các phương thức của họ
  • cung cấp siêu dữ liệu thời gian chạy Objective-C cho (hầu hết) việc triển khai phương pháp của họ

Các lớp Swift không phải là các lớp con của NSObject:

  • là các lớp Objective-C, nhưng chỉ triển khai một số phương pháp để tương thích với NSObject
  • không sử dụng objc_msgSend()cho các cuộc gọi đến phương thức của họ (theo mặc định)
  • không cung cấp siêu dữ liệu thời gian chạy Objective-C để triển khai phương thức của chúng (theo mặc định)

Phân lớp NSObject trong Swift giúp bạn linh hoạt trong thời gian chạy Objective-C mà còn cả hiệu suất Objective-C. Tránh NSObject có thể cải thiện hiệu suất nếu bạn không cần tính linh hoạt của Objective-C.

Biên tập:

Với Xcode 6 beta 6, thuộc tính động sẽ xuất hiện. Điều này cho phép chúng tôi hướng dẫn Swift rằng một phương thức nên sử dụng điều phối động và do đó sẽ hỗ trợ việc đánh chặn.

public dynamic func foobar() -> AnyObject {
}

1
Swift sử dụng loại công văn nào thay vì objc_msgSend? Nó có tĩnh không?
Bill

12
Swift có thể sử dụng công văn objc_msgSend, công văn bảng ảo, công văn trực tiếp hoặc nội tuyến.
Greg Parker

static: ít hơn 1,1ns. vtable 1.1ns, msgSend 4.9ns. . (Tất nhiên phụ thuộc vào phần cứng). . Có vẻ như Swift 'thuần túy' tạo ra một ngôn ngữ tuyệt vời cho lập trình cấp hệ thống, nhưng đối với ứng dụng, tôi không muốn bỏ qua các tính năng động, mặc dù tôi sẽ rất vui nếu họ chuyển sang trình biên dịch như trong Garbage Collection vs ARC. . . Tôi đã nghe nó nói rằng điều phối tĩnh cho phép dự đoán nhánh tốt hơn (và do đó hiệu suất) trên các sytems đa lõi. Thật?
Jasper Blues

"Các lớp Swift không phải là lớp con của NSObject là các lớp Objective-C" - bạn có thể cung cấp liên kết đến nơi bạn tìm thấy điều đó đã nêu không?
Matt S.

1
Vì vậy, tóm lại tôi chỉ nên phân lớp NSObject trong Swift nếu tôi cần giao tiếp với mã Objective C?
MobileMon

14

Tôi cũng nhận thấy rằng nếu dựa trên một lớp Swift trên NSObject, tôi đã thấy một số hành vi thời gian chạy không mong muốn có thể ẩn các lỗi mã hóa. Đây là một ví dụ.

Trong ví dụ này, nơi chúng tôi không dựa trên NSObject, trình biên dịch phát hiện chính xác lỗi trong testIncorrect_CompilerShouldSpot, báo cáo "... 'MyClass' không thể chuyển đổi thành 'MirrorDisposition'"

class MyClass {
  let mString = "Test"

  func getAsString() -> String {
    return mString
  }

  func testIncorrect_CompilerShouldSpot() {
    var myString = "Compare to me"
      var myObject = MyClass()
      if (myObject == myString) {
        // Do something
      }
  }

  func testCorrect_CorrectlyWritten() {
    var myString = "Compare to me"
      var myObject = MyClass()
      if (myObject.getAsString() == myString) {
        // Do something
      }
  }
}

Trong ví dụ này, khi chúng tôi dựa trên NSObject , trình biên dịch không phát hiện ra lỗi trong testIncorrect_CompilerShouldSpot:

class myClass : NSObject {
  let mString = "Test"

  func getAsString() -> String {
    return mString
  }

  func testIncorrect_CompilerShouldSpot() {
    var myString = "Compare to me"
      var myObject = MyClass()
      if (myObject == myString) {
        // Do something
      }
  }

  func testCorrect_CorrectlyWritten() {
    var myString = "Compare to me"
      var myObject = MyClass()
      if (myObject.getAsString() == myString) {
        // Do something
      }
  }
}

Tôi đoán đạo đức là, chỉ dựa trên NSObject nơi bạn thực sự phải làm!


1
Cảm ơn bạn về thông tin.
Jasper Blues

13

Theo tham chiếu ngôn ngữ, không có yêu cầu đối với các lớp phải phân lớp bất kỳ lớp gốc tiêu chuẩn nào, vì vậy bạn có thể bao gồm hoặc bỏ qua một lớp cha nếu cần.

Lưu ý rằng việc bỏ qua một lớp cha khỏi khai báo lớp, sẽ không gán một lớp cha cơ sở ngầm định của bất kỳ loại nào. Nó định nghĩa một lớp cơ sở, lớp này sẽ trở thành gốc cho một hệ thống phân cấp lớp độc lập.

Từ tham chiếu ngôn ngữ:

Các lớp Swift không kế thừa từ một lớp cơ sở phổ quát. Các lớp bạn xác định mà không chỉ định lớp cha sẽ tự động trở thành lớp cơ sở để bạn xây dựng.

Cố gắng tham chiếu supertừ một lớp không có siêu lớp (tức là lớp cơ sở) sẽ dẫn đến lỗi thời gian biên dịch

'super' members cannot be referenced in a root class

1
Vâng. Nếu bạn cố gắng tạo tệp nguồn Cocoa hoặc Cocoa Touch trong ngữ cảnh của một dự án, biểu mẫu mà bạn chèn lớp con thực sự ngăn bạn tạo lớp trong khi để trống. Bạn có thể xóa lớp cha sau khi nó đã được tạo.
Cezar

1
Cảm ơn. Sử dụng công văn tĩnh và vtable có ý nghĩa đối với lập trình hệ thống hoặc điều chỉnh hiệu suất. Để nhất quán với Cacao nguyên bản, tôi nghĩ động nên là mặc định. (Trừ khi ai đó có thể thuyết phục tôi bằng cách khác, do đó, câu hỏi này).
Jasper Blues

1

Tôi tin rằng phần lớn dữ liệu Swift sẽ không như vậy objc. Chỉ những phần cần giao tiếp với cơ sở hạ tầng Mục tiêu C mới được đánh dấu rõ ràng như vậy.

Tôi không biết nội quan thời gian chạy sẽ được thêm vào ngôn ngữ ở mức độ nào. Việc đánh chặn phương thức có thể chỉ trở nên khả thi nếu phương thức đó cho phép một cách rõ ràng. Đây là suy đoán của tôi, nhưng chỉ những nhà thiết kế ngôn ngữ của Apple mới thực sự biết họ đang thực sự hướng tới đâu.


Đối với tôi, việc đặt tính năng động là mặc định (thông qua việc mở rộng NSObject, sử dụng trang trí '@objc' hoặc một số cách tiếp cận khác) có ý nghĩa. Có vẻ như khi không có lớp cơ sở, Swift sẽ ưu tiên gửi tĩnh / vtable, điều này hoạt động tốt hơn, nhưng trong hầu hết các trường hợp, điều này sẽ không cần thiết. . (90% lợi nhuận đến từ việc điều chỉnh 10% mã). Hy vọng của tôi là sự nhất quán với tính năng động của Objective-C là chọn không tham gia thay vì chọn tham gia.
Jasper Blues

Cách ngôn ngữ được thiết kế, nó là tùy chọn tham gia. Theo những gì chúng tôi biết, rất có thể trong tương lai, các API hệ thống sẽ được thêm vào mà không phải là nguyên nhân phản đối. Về trung hạn / dài hạn, họ thậm chí có thể di chuyển các thư viện hiện có sang mã không phải objc với một lớp tương thích mỏng trong objc gọi vào mã không objc. Chúng tôi chỉ không biết. Chúng tôi có thể sẽ kiếm được educated guessessau vài năm kể từ bây giờ. Nhưng hiện tại đó chỉ là một dấu hỏi lớn.
Tệp Analog

@JasperBlues Tôi tranh luận rằng hầu hết thời gian không cần đến tính năng động và tôi muốn có hiệu suất theo mặc định và sau đó chọn tham gia vào hành vi động là cần thiết. Để mỗi Tôi đoán riêng của mình :)
Lance

@Lance Hừm. Có lẽ. Tôi vẫn lo lắng về: quan sát viên, AOP, khuôn khổ chế tạo thử nghiệm, khuôn khổ phân tích, v.v. và vấn đề về hiệu suất là 90% lợi nhuận đến từ việc điều chỉnh 10%. . vì vậy đó là lý do của tôi - chọn tham gia cho 10% trường hợp đó. Tôi nghĩ AOP sẽ là một vấn đề lớn đối với các ứng dụng doanh nghiệp iOS, nhưng nó có thể được thực hiện bằng cách sử dụng một công cụ biên dịch như trong C ++. . chắc chắn các trò chơi, máy tính khoa học, đồ họa, v.v. các nhà phát triển sẽ hoan nghênh hiệu suất cao hơn :)
Jasper Blues

1

Phần sau được sao chép từ Swift-eBook của Apple và đưa ra câu trả lời thích hợp cho câu hỏi của bạn:

Xác định Lớp cơ sở

Bất kỳ lớp nào không kế thừa từ lớp khác được gọi là lớp cơ sở.

Các lớp Swift không kế thừa từ một lớp cơ sở phổ quát. Các lớp bạn xác định mà không chỉ định lớp cha sẽ tự động trở thành lớp cơ sở để bạn xây dựng.


Tài liệu tham khảo

https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Inheritance.html#//apple_ref/doc/uid/TP40014097-CH17-XID_251


-6

Thật là bình thường. Nhìn vào mục tiêu thiết kế của Swift: Mục tiêu là làm biến mất các lớp lập trình khổng lồ. Thay đổi phương thức có lẽ không phải là một trong những điều bạn muốn làm với Swift.


3
Phương pháp swizzling là một cách để đạt được mô hình đánh chặn trong thời gian chạy. Một trong những cách sử dụng cho việc này là áp dụng các mối quan tâm xuyên suốt theo các nguyên tắc của Lập trình hướng theo khía cạnh. Các thông báo của riêng Apple, bộ quan sát tài sản (tích hợp sẵn để nhanh chóng), dữ liệu cốt lõi đều sử dụng hiệu quả nhanh chóng. . Một trong những điều khiến mọi người say mê Objective-C mặc dù cú pháp khó hiểu của nó là tính năng động này, giúp dễ dàng cung cấp các giải pháp thanh lịch bất cứ khi nào mẫu đánh chặn được yêu cầu. . thực tế là không có khuôn khổ AOP chính thức nào cho Objc, bởi vì nguyên liệu thô quá tốt.
Jasper Blues

Thực tế rằng đây là cách nó được thực hiện bây giờ không có nghĩa là nó sẽ được thực hiện vào ngày mai. Như bạn nói thông báo, người quan sát tài sản, người được ủy quyền và những thứ tương tự được hoặc có thể được cung cấp nguyên bản. Ngôn ngữ sẽ phát triển, và chúng tôi không biết theo hướng nào. Nó đã đạt được rất nhiều về mặt hỗ trợ cho lập trình chức năng. Nhưng nó làm điều đó theo một cách khác thường, vì vậy tôi không biết mình còn thiếu bao nhiêu. Tuy nhiên, theo như chúng tôi biết, họ có thể đang hướng tới việc không khuyến khích đột biến và khuyến khích lập trình chức năng thuần túy. Điều gì sẽ xảy ra nếu tương lai của giao diện người dùng là phản ứng? Không có cách nào để biết được nêu ra.
Tệp tương tự

1
Có, nhưng tất cả những điều này phụ thuộc vào việc đánh chặn, có thể được thực hiện theo hai cách: thời gian biên dịch (C ++) hoặc thời gian chạy (Ruby, Objective-C, Java (thông qua asm, cglib, ApsectJ, v.v.)). Các ngôn ngữ hiện đại có xu hướng làm điều đó trong thời gian chạy. Mọi người yêu thích Objective-C, vì nó hoạt động giống như một ngôn ngữ hiện đại mặc dù là một codger cũ. Giống như bạn nói, càng nhiều nội dung này được đưa vào ngôn ngữ thì càng tốt (miễn là nó được thực hiện tốt!). . nhưng hiện tại, chúng tôi có thể tiếp cận với di sản do Objc / Foundation cung cấp, đó là lý do tại sao tôi hy vọng việc mở rộng NSObject trở thành thông lệ tiêu chuẩn cho các ứng dụng hàng ngày trong vài năm tới.
Jasper Blues
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.