Швидкий рідний базовий клас або NSObject


105

Я перевірив, що Swift шифрує Іса , і виявив, що він працює лише тоді, коли NSObject - це суперклас (безпосередньо чи далі вгору), або використовуючи прикрасу '@objc'. В іншому випадку він буде дотримуватися статичного та vtable-диспетчерського стилів, як C ++.

Чи нормально визначати клас Swift без базового класу Cocoa / NSObject? Якщо мене це турбує, це означає, що більша частина динамізму об'єктивності-С, наприклад перехоплення методів та самоаналіз часу виконання.

Динамічна поведінка під час роботи лежить в основі таких функцій, як спостерігачі власності, основні дані, орієнтоване на аспекти програмування , обмін повідомленнями вищого порядку , аналітичні та журнальні системи тощо.

Використання стилю виклику методу Objective-C додає близько 20 операндів машинного коду до виклику методу, тому в певних ситуаціях ( багато жорстких дзвінків до методів із невеликими тілами ) статична та віртуальна диспетчеризація стилю C ++ може працювати краще.

Але враховуючи загальне правило 95-5 ( 95% підвищення продуктивності відбувається від настройки 5% коду ), чи не має сенсу починати з потужних динамічних функцій і загартовувати там, де це необхідно?


Пов’язано: Чи підтримує Swift аспектно-орієнтоване програмування? stackoverflow.com/a/24137487/404201
Джаспер Блюз

Відповіді:


109

Класи Swift, які є підкласами NSObject:

  • є самими класами Objective-C
  • використовувати objc_msgSend()для викликів (більшість) своїх методів
  • забезпечити метадані об’єктів виконання C (Objective-C) для більшості реалізацій їх методів

Класи Swift, які не є підкласами NSObject:

  • є класами Objective-C, але реалізують лише декілька методів сумісності NSObject
  • не використовувати objc_msgSend()для викликів їх методів (за замовчуванням)
  • не надавати метадані об’єкта виконання Cube Objective-C для їх реалізації (за замовчуванням)

Підкласифікація NSObject в Swift отримує гнучкість виконання Objective-C, але і продуктивність Objective-C. Уникнення NSObject може підвищити продуктивність, якщо вам не потрібна гнучкість Objective-C.

Редагувати:

З Xcode 6 beta 6 з'являється динамічний атрибут. Це дозволяє нам доручити Swift, що метод повинен використовувати динамічну диспетчеризацію, і тому підтримуватиме перехоплення.

public dynamic func foobar() -> AnyObject {
}

1
Яку розсилку використовує Swift замість objc_msgSend? Це статично?
Білл

12
Swift може використовувати objc_msgSend диспетчеризацію, віртуальну таблицю, пряму або вбудовану лінію.
Грег Паркер

статичний: менше 1,1ns. vtable 1.1ns, msgSend 4.9ns. . (Залежно від апаратури, звичайно). . Здається, «чистий» Swift чудовою мовою для програмування на системному рівні, але для додатків я б не бажав відмовлятися від динамічних функцій, хоча був би радий, якби вони перейшли до компілятора як у «Garbage Collection vs ARC». . . Я чув, як говорилося, що статична диспетчеризація дозволяє краще прогнозувати гілки (і, таким чином, продуктивність) для багатоядерних систем. Правда?
Джаспер Блюз

"Класи Swift, які не є підкласами NSObject, є класами Objective-C" - чи можете ви надати посилання на те, де ви виявили, що зазначено?
Метт С.

1
Отже, підсумовуючи, я повинен лише підклас NSObject у Swift, якщо мені потрібно спілкуватися з кодом Objective C?
MobileMon

14

Я також виявив, що якщо ґрунтувати клас Swift на NSObject, я побачив деяку несподівану поведінку під час роботи, яка може приховати помилки кодування. Ось приклад.

У цьому прикладі, коли ми не базуємось на NSObject, компілятор правильно помічає помилку в testIncorrect_CompilerShouldSpot, повідомляючи "..." MyClass "не можна конвертувати в" 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
      }
  }
}

У цьому прикладі, де ми базуємось на NSObject , компілятор не помічає помилку в 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
      }
  }
}

Я думаю, мораль - це лише база на NSObject, де ви дійсно повинні!


1
Дякуємо за інформацію.
Джаспер Блюз

13

Згідно з посиланням на мову, для класів не існує вимоги до підкласу будь-якого стандартного кореневого класу, тому ви можете включити або пропустити надклас за потребою.

Зауважте, що опускання суперкласу з декларації класу не призначає неявного базового надкласу будь-якого типу. Він визначає базовий клас, який фактично стане коренем незалежної ієрархії класів.

З мовної довідки:

Класи Swift не успадковують від універсального базового класу. Класи, які ви визначаєте, не вказуючи суперклас, автоматично стають базовими класами, на яких ви будете будуватись.

Спроба посилання superз класу без суперкласу (тобто базового класу) призведе до помилки часу компіляції

'super' members cannot be referenced in a root class

1
Так. Якщо ви спробуєте створити вихідний файл Cocoa Or Cocoa Touch у контексті проекту, форма, в яку ви вставляєте підклас, насправді заважає створювати клас, залишаючи його порожнім. Ви можете видалити суперклас пізніше після його створення.
Цезар

1
Дякую. Використання статичної та vtable диспетчеризації має сенс для програмування систем або налаштування продуктивності. Щодо узгодженості з рідним какао, я вважаю, що динамік повинен бути типовим. (Якщо хтось не може переконати мене в іншому, звідси це питання).
Джаспер Блюз

1

Я вважаю, що переважна більшість даних Swift не буде objc. Тільки ті частини, які потребують зв'язку з інфраструктурою Objective C, будуть чітко позначені як такі.

Якою мірою самоаналіз часу виконання буде доданий до мови, я не знаю. Перехоплення методів, ймовірно, стане можливим лише в тому випадку, якщо метод прямо дозволяє. Це я здогадуюсь, але лише мовні дизайнери в Apple справді знають, куди вони насправді прямують.


Для мене має сенс зробити динамізм за замовчуванням (через розширення NSObject, використовуючи декор '@objc' або інший підхід). Здається, коли базового класу немає, Swift надасть перевагу статичній / вибійній диспетчері, яка працює краще, але в більшості випадків це не буде потрібно. . (90% виграшів відбувається від настройки 10% коду). Я сподіваюся, що узгодженість з динамізмом Objective-C є відмовою, а не відключенням.
Джаспер Блюз

Спосіб розроблення мови - необов'язковий вибір. Наскільки нам відомо, цілком може бути, що в майбутньому системні API будуть додані, які не є споконвічно objc. У середньому / довгостроковому періоді вони можуть навіть мігрувати існуючі бібліотеки до не objc коду з тонким шаром сумісності в objc, який викликає код non objc. Ми просто не знаємо. Ми, мабуть, зможемо зробити educated guessesчерез кілька років. Але на даний момент це просто великий знак питання.
Аналоговий файл

@JasperBlues Я б заперечував, що динамізм не потрібен більшу частину часу, і я вважаю за краще мати продуктивність за замовчуванням, а потім увімкнути динамічну поведінку. Я думаю, що для кожного його власне :)
Lance

@ Ленс Хммм. Може бути. Мене все ще турбують: спостерігачі, АОП, тестові макетні рамки, аналітичні рамки тощо. і річ у продуктивності полягає в тому, що 90% прибутку припадає на налаштування 10%. . тож це моє обґрунтування - відмовитись у тих 10% випадків. Я думаю, що AOP буде великою справою для корпоративних додатків iOS, але це можна зробити за допомогою інструмента компілятора, як це є в C ++. . безумовно, ігри, наукові обчислення, графіка та ін. розробники вітатимуть більшу продуктивність :)
Jasper Blues

1

З Swift-eBook від Apple скопійовано наступне та дає відповідну відповідь на ваше запитання:

Визначення базового класу

Будь-який клас, який не успадковує інший клас, відомий як базовий клас.

Класи Swift не успадковують від універсального базового класу. Класи, які ви визначаєте, не вказуючи суперклас, автоматично стають базовими класами, на яких ви будете будуватись.


Довідково

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


-6

Це нормально. Подивіться на цілі дизайну Swift: мета полягає в тому, щоб величезні класи проблем програмування зникли. Швидкість методу - це, мабуть, не одна з речей, якими ви хочете займатися зі Свіфтом.


3
Метод свистування - це спосіб досягти схеми перехоплення під час виконання. Одним із застосувань для цього є застосування наскрізних проблем відповідно до принципів орієнтованого на аспекти програмування. Власні сповіщення від Apple, спостерігачі за властивостями (вбудовані для швидкого переходу), основні дані - це все, що використовується для швидкого ефекту. . Однією з речей, які закохали людей у ​​Objective-C, незважаючи на його незграбний синтаксис, був цей динамізм, який дозволяє легко пропонувати вишукані рішення, коли потрібен шаблон перехоплення. . насправді для Objc не було офіційної рамки АОП, оскільки сировина була такою доброю.
Джаспер Блюз

Те, що зараз це робиться, не означає, що це буде завтра. Як ви говорите, спостереження, спостерігачі за майном, делегати тощо можуть надаватися або можуть бути надані на місцях. Мова буде розвиватися, і ми не знаємо, в якому напрямку. Він отримав багато в плані підтримки функціонального програмування. Але це робить це незвично, тому я поняття не маю, скільки цього бракує. Однак, наскільки ми знаємо, вони, можливо, спрямовуються на відмову від мутації та заохочення до чистого функціонального програмування. Що робити, якщо майбутнє інтерфейсу буде реактивним? Ще не знаю.
Аналоговий файл

1
Так, але все це залежить від перехоплення, яке може здійснюватися двома способами: час компіляції (C ++) або час виконання (Ruby, Objective-C, Java (через asm, cglib, ApsectJ тощо). Сучасні мови, як правило, роблять це під час виконання. Люди любили Objective-C, тому що він поводився як сучасна мова, незважаючи на те, що був старим кодером. Як ви кажете, чим більше цього випечене на мові, тим краще (за умови, що це зроблено добре!). . але поки що ми можемо підключитися до спадщини, наданої Objc / Foundation, тому я сподіваюся, що розширення NSObject стає стандартною практикою для щоденних додатків протягом наступних кількох років.
Джаспер Блюз
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.