Компания
459,86
рейтинг
7 июля 2014 в 11:50

Разработка → Особенности Swift

В рамках Mobile Camp Яндекса наш коллега Денис Лебедев представил доклад о новом языке программирования Swift. В своем докладе он затронул особенности взаимодействия с Objective-C, рассказал про фичи языка, которые показались ему наиболее интересными. А также про то куда сходить на Github, и какие репозитории посмотреть, чтобы понять, что со Swift можно делать в реальном мире.

Разработка Swift началась в 2010 году. Занимался ей Крис Латтнер. До 2013 процесс шел не очень активно. Постепенно вовлекалось все больше людей. В 2013 году Apple сфокусировалась на разработке этого языка. Перед презентацией на WWDC о Swift знало порядка 200 человек. Информация о нем хранилась в строжайшем секрете.




Swift – мультипарадигменный язык. В нем есть ООП, можно пробовать некоторые функциональные вещи, хотя адепты функционального программирования считают, что Swift немного не дотягивает. Но, мне кажется, что такая цель и не ставилась, все-таки это язык для людей, а не для математиков. Можно писать и в процедурном стиле, но я не уверен, что это применимо для целых проектов. Очень интересно в Swift все устроено с типизацией. В отличие от динамического Objective-C, она статическая. Также есть вывод типов. Т.е. большинство деклараций типов переменных можно просто опустить. Ну и киллер-фичей Swift можно считать очень глубокое взаимодействие с Objective-C. Позже я расскажу про runtime, а пока ограничимся тем, что код из Swift можно использовать в Objective C и наоборот. Указатели привычные всем разработчикам на Objective-С и С++ в Swift отсутствуют.

Перейдем к фичам. Их достаточно много. Я для себя выделил несколько основных.
  • Namespacing. Все понимают, проблему Objective-C – из-за двухбуквенных и трехбуквенных классов часто возникают коллизии имен. Swift решает эту проблему, вводя очевидные и понятные всем нэймспейсы. Пока они не работают, но к релизу все должны починить.
  • Generic classes & functions. Для людей, которые писали на С++, это достаточно очевидная вещь, но для тех, кто сталкивался в основном с Objective-C, это достаточно новая фича, с которой будет интересно поработать.
  • Named/default parameters. Именованными параметрами никого не удивишь, в Objective-C они уже были. А вот параметры по умолчанию – очень полезная штука. Когда у нас метод принимает пять аргументов, три из которых заданы по умолчанию, вызов функции становится гораздо короче.
  • Functions are first class citizens. Функции в Swift являются объектами первого порядка. Это означает, что их можно передавать в другие методы как параметры, а также возвращать их из других методов.
  • Optional types. Необязательные типы – интересная концепция, которая пришла к нам в слегка видоизмененном виде из функционального программирования.

Рассмотрим последнюю фичу немного подробнее. Все мы привыкли, что в Objective-C, когда мы не знаем, что вернуть, мы возвращаем nil для объектов и -1 или NSNotFound для скаляров. Необязательные типы решают эту проблему достаточно радикально. Optional type можно представить как коробку, которая либо содержит в себе значение, либо не содержит ничего. И работает это с любыми типами. Предположим, что у нас есть вот такая сигнатура:

(NSInteger) indexOfObjec: (id)object;

В Objective-C неясно, что возвращает метод. Если объекта нет, то это может быть -1, NSNotFound или еще какая-нибудь константа известная только разработчику. Если мы рассмотрим такой же метод в Swift, мы увидим Int со знаком вопроса:

func indexOF(object: AnyObject) -> Int?

Эта конструкция говорит нам, что вернется либо число, либо пустота. Соответственно, когда мы получили запакованный Int, нам нужно его распаковать. Распаковка бывает двух видов: безопасная (все оборачивается в if/else) и принудительная. Последнюю мы можем использовать только если мы точно знаем, что в нашей воображаемой коробке будет значения. Если его там не окажется, будет крэш в рантайме.

Теперь коротко поговорим про основные фичи классов, структур и перечислений.Главное отличие классов от структур заключается в том, что они передаются по ссылке. Структуры же передаются по значению. Как говорит нам документация, использование структур затрачивает гораздо меньше ресурсов. И все скалярные типы и булевы переменные реализованы через структуры.

Перечисления хотелось бы выделить отдельно. Они абсолютно отличаются от аналогов в C, Objective-C и других языках. Это комбинация класса, структуры и даже немного больше. Чтобы показать, что я имею в виду, рассмотрим пример. Предположим, что я хочу реализовать дерево с помощью enum. Начнем с небольшого перечисления с тремя элементами (пустой, узел и лист):

enum Tree {
	case Empty
	case Leaf
	case Node
}

Что с этим делать пока неясно. Но в Swift каждый элемент enum может нести какое-то значение. Для этого мы у листа добавим Int, а у узла будет еще два дерева:

enum Tree {
	case Empty
	case Leaf(Int)
	case Node(Tree, Tree)
}

Но так как Swift поддерживает генерики, мы добавим в наше дерево поддержку любых типов:

enum Tree<T> {
	case Empty
	case Leaf(T)
	case Node(Tree, Tree)
}

Объявление дерева будет выглядеть примерно так:

let tree: Tree<Int> = .Node(.Leaf(1), .Leaf(1))

Здесь мы видим еще одну крутую фичу: мы можем не писать названия перечислений, потому что Swift выводит эти типы на этапе компиляции.

У enum в Swift есть еще одна интересная особенность: они могут содержать в себе функции, точно так же, как в структурах и классах. Предположим, что я хочу написать функцию, которая вернет глубину нашего дерева.

enum Tree {
	case Empty
	case Leaf(Int)
	case Node(Tree, Tree)

	func depth<T>(t: Tree<T>) -> Int {
		return 0
	}
}

Что мне в этой функции не нравится, так это то, что она принимает параметр дерева. Я хочу сделать так, чтобы функция просто возвращала мне значения, а мне ничего передавать бы не требовалось. Здесь мы воспользуемся еще одной интересной фичей Swift: вложенными функциями. Т.к. модификаторов доступа пока нет – это один из способов сделать функцию приватной. Соответственно, у нас есть _depth, которая сейчас будет считать глубину нашего дерева.

enum Tree<T> {
	case …

	func depth() -> Int {
		func _depth<T>(t: Tree<T>) -> Int {
			return 0
		}
		return _depth(self)
	}
}

Мы видим стандартный свитч, тут нет ничего свифтового, просто обрабатываем вариант, когда дерево пустое. Дальше начинаются интересные вещи. Мы распаковываем значение, которое хранится у нас в листе. Но так как оно нам не нужно, и мы хотим просто вернуть единицу, мы используем подчеркивание, которое означает, что переменная в листе нам не нужна. Дальше мы мы распаковываем узел, из которого мы достаем левую и правую части. Затем вызываем рекурсивно функцию глубины и возвращаем результат. По итогу у нас получается такое вот реализованное на enum дерево c какой-то базовой операцией.

enum Tree<T> {
	case Empty
	case Leaf(T)
	case Node(Tree, Tree)
	

	func depth() -> Int {
		func _depth<T>(t: Tree<T>) -> Int {
			switch t {
			case .Empty:
				return 0
			case .Leaf(let_):
				return 1
			case .Node(let lhs, let rhs):
				return max(_depth(lhs), _depth(rhs))
			}
		}
		return _depth(self)
	}
}

Интересная штука с этим enum заключается в том, что этот написанный им код, должен работать, но не работает. В текущей версии из-за бага enum не поддерживает рекурсивные типы. В будущем это все заработает. Пока для обхода этого бага используются разные хаки. Про один из них я расскажу чуть позже.

Следующий пункт моего моего рассказа – это коллекции, представленные в стандартной библиотеке массивом, словарями и строкой (коллекция чаров). Коллекции, как и скаляры, являются структурами, они также взаимозаменяемы со стандартными foundation-типами, такими как NSDictionary и NSArray. Кроме того, мы видим, что по какой-то странной причине нет типа NSSet. Вероятно, им слишком редко пользуются. В некоторых операциях (например, filter и reverse) есть ленивые вычисления:

func filter<S :Sequence>(…) -> Bool) ->
	FilterSequenceView<S>

func reverce<S :Collection …>(source: C) ->
	ReverseView<C>

Т.е. типы FilterSequenceView и ReverseView – это не обработанная коллекция, а ее представление. Это говорит нам о том, что у этих методов высокая производительность. В том же Objective-C таких хитрых конструкций не встретишь, так как во времена создания этого языка о таких концепциях никто еще не думал. Сейчас lazy-вычисления проникают в языки программирования. Мне нравится эта тенденция, иногда это бывает очень эффективно.

Следующую фичу заметили уже, наверное, все, кто как-то интересовался новым языком. Но я все равно про нее расскажу. В Swift есть встроенная неизменяемость переменных. Мы можем объявить переменную двумя способами: через var и let. В первом случае переменные могут быть изменены, во втором – нет.

var и = 3
b += 1

let a = 3
a += 1 // error

Тут начинается интересная вещь. Например, если мы посмотрим на словарь, который объявлен с помощью директивы let, то при попытке изменения ключа или добавления нового, мы получим ошибку.

let d = ["key": 0]
d = ["key"] = 3 //error
d.updateValue(1, forKey: "key1") //error

С массивами все обстоит несколько иначе. Мы не можем увеличивать размер массива, но при этом мы можем изменять любой из его элементов.

let c = [1, 2, 3]
c[0] = 3 // success
c.append(5) // fail

На самом деле это очень странно, при попытке разобраться, в чем дело, выяснилось, что это подтвержденный разработчиком языка баг. В ближайшем будущем он будет исправлен, т.к. это действительно очень странное поведение.

Расширения в Swift очень похожи на категории из Objective-C, но больше проникают в язык. В Swift не нужно писать импорты: мы можем в любом месте в коде написать расширение, и оно подхватится абсолютно всем кодом. Соответственно, тем же образом можно расширять структуры и енамы, что тоже иногда бывает удобно. При помощи расширений можно очень хорошо структурировать код, это реализовано в стандартной библиотеке.

struct: Foo {
	let value : Int
}

extension Foo : Printable {
	var description : String {
		get {return "Foo"}
	}
}

extension Foo : Equatable {

}

func ==(lhs: Foo, rhs: Foo) -> Bool {
	return lhs.value == rhs.value
}

Далее поговорим о том, чего в Swift нет. Я не могу сказать, что чего-то конкретного мне не хватает, т.к. в продакшене я его пока не использовал. Но есть вещи, на которые многие жалуются.
  • Preprocessor. Понятно, что если нет препроцессора, то нет и тех крутых макросов, которые генерят за нас очень много кода. Также затрудняется кроссплатформенная разработка.
  • Exceptions. Механизм эксепшенов полностью отсутстсует, но можно создаст NSException, и рантайм Objective-C все это обработает.
  • Access control. После прочтения книги о Swift многие пришли в замешательство из-за отсутствия модификаторов доступа. В Objective-C этого не было, все понимали, что это необходимо, и ждали в новом языке. На самом деле, разработчики просто не успели имплементировать модификаторы доступа к бета-версии. В окончательном релизе они уже будут.
  • KVO, KVC. По понятным причинам нет Key Value Observing и Key Value Coding. Swift – статический язык, а это фичи динамичесих языков.
  • Compiler attributes. Отсутствуют директивы компилятора, которые сообщают о deprecated-методах или о том, есть ли метод на конкретной платформе.
  • performSelector. Этот метод из Swift полностью выкосили. Это достаточно небезопасная штука и даже в Objective-C ее нужно использовать с оглядкой.

Теперь поговорим о том, как можно мешать Objective-C и Swift. Все уже знают, что из Swift можно вызвать код на Objective-C. В обратную сторону все работает точно так же, но с некоторыми ограничениями. Не работают перечисления, кортежи, обобщенные типы. Несмотря на то, что указателей нет, CoreFoundation-типы можно вызывать напрямую. Для многих стала расстройством невозможность вызывать код на С++ напрямую из Swift. Однако можно писать обертки на Objective-C и вызывать уже их. Ну и вполне естественно, что нельзя сабклассить в Objective-C нереализованные в нем классы из Swift.

Как я уже говорил выше, некоторые типы взаимозаменяемы:
  • NSArray < - > Array;
  • NSDictionary < - > Dictionary;
  • NSNumber - > Int, Double, Float.


Приведу пример класса, который написан на Swift, но может использоваться в Objective-C, нужно лишь добавить одну директиву:
@objc class Foo {
	int (bar: String) { /*...*/}
} 

Если мы хотим, чтобы класс в Objective-C имел другое название (например, не Foo, а objc_Foo), а также поменять сигнатуру метода, все становится чуточку сложнее:

@objc(objc_Foo)
class Foo{
	
	@objc(initWithBar:)
	init (bar: String) { /*...*/}
}

Соответственно, в Objective-C все выглядит абсолютно ожидаемо:

Foo *foo = [[Foo alloc] initWithBar:@"Bar"];

Естественно, можно использовать все стандартные фреймворки. Для всех хедеров автоматически генерируется их репрезентация на Swift. Допустим, у нас есть функция convertPoint:

- (CGPoint)convertPoint:(CGPoint)point toWindow:(UIWindow *)window

Она полностью конвертируется в Swift с единственным отличием: около UIWindow есть восклицательный знак. Это указывает на тот самый необязательный тип, про который я говорил выше. Т.е. если там будет nil, и мы это не проверим, будет крэш в рантайме. Это происходит из-за того, что когда генератор создает эти хедеры, он не знает, может быть там nil или нет, поэтому и ставит везде эти восклицательные знаки. Возможно, скоро это как-нибудь поправят.

finc convertPoint(point: CGPoint, toWindow window: UIWindow!) -> GCPoint

Подробно, говорить о внутренностях и перформансе Swift пока рано, так как неизвестно, что из текущего рантайма доживет до первой версии. Поэтому пока что коснемся этой темы лишь поверхностно. Начнем с того, что все Swift-объекты – это объекты Objective-C. Появляется новый рутовый класс SwiftObject. Методы теперь хранятся не с классами, а в виртуальных таблицах. Еще одна интересная особенность – типы переменных хранятся отдельно. Поэтому декодировать классы налету становится чуть сложнее. Для кодирования метаданных методов используется подход называемый name mangling. Для примера посмотрим на класс Foo с методом bar, возвращающим Bool:
class Foo {
	func bar() -> Bool {
		return false
	}
}

Если мы посмотрим в бинарник, для метода barмы увидим сигнатуру следующего вида: _TFC9test3Foo3barfS0_FT_Sb. Тут у нас есть Foo с длиной 3 символа, длина метода также 3 символа, а Sb в конце означает, что метод возвращает Bool. C этим связана не очень приятная штука: дебаг-логи в XCode все попадает именно в таком, виде, поэтому читать их не очень удобно.
Наверное все уже читали про то, что Swift очень медленный. По большому счету это так и есть, но давайте попробуем разобраться. Если мы будем компилировать с флагом -O0, т.е. без каких-либо оптимизаций, то Swift будет медленнее С++ от 10 до 100 раз. Если компилировать с флагом -O3, мы получим нечно в 10 раз медленнее С++. Флаг -Ofast не очень безопасен, так как отключает в рантайме проверки переполнения интов и т.п. В продакшене его лучше не использовать. Однако он позволяет повысить производительность до уровня С++.
Нужно понимать, что язык очень молодой, он все еще в бете. В будущем основные проблемы с быстродействием будут фикститься. Кроме того, за Swift тянется наследие Objective-C, например, в циклах есть огромное количество ретэйнов и релизов, которые в Swift по сути не нужны, но очень тормозят быстродействие.

Дальше я буду рассказывать про не очень связанные друг с другом вещи, с которыми я сталкивался в процессе разработки. Как я уже говорил выше, макросы не поддерживаются, поэтому единственный способ сделать кроссплатформенную вьюшку выглядит следующим образом:

#if os(iOS)
	typealias View = UView
#else
	typealias View = NSView
#endif

class MyControl : View {
	
}

Этот if – это не совсем препроцессор, а просто конструкция языка, которая позволяет проверить платформу. Соответственно, у на есть метод, который нам возвращает, на какой мы платформе. В зависимости от этого мы делаем алиас на View. Таким образом мы создаем MyControl, который будет работать и на iOS и на OS X.

Следующая фича – сопоставление с образцом – мне очень нравится. Я немного увлекаюсь функциональными языками, там она используется очень широко. Возьмем для примера задачу: у нас есть точка на плоскости, и мы хотим понять, в каком из четырех квадрантов она находится. Все мы представляем, что это будет за код в Objective-C. Для каждого квадранта у нас будут вот такие абсолютно дикие условия, где мы должны проверять попадают ли x и y в эти рамки:

let point = (0, 1)

if point.0 >= 0 && point.0 <= 1 &&
   point.1 >= 0 && point.1 <= 1  {
   	println("I")
   }
...

Swift нам в этом случае нам дает несколько удобных штук. Во-первых, у нас появляется хитрый range-оператор с тремя точками. Соответственно, case может проверить, попадает ли точка в первый квадрант. И весь код будет выглядеть примерно таким образом:

let point = (0, 1)

switch point {
	case (0, 0)
		println("Point is at the origin")
	case (0...1, 0...1):
		println("I")
	case (-1...0, 0...1):
		println("II")
	case (-1...0, -1...0):
		println("III")
	case (0...1, -1...0):
		println("IV")
	default:
		println("I don't know")
}

На мой взгляд это в десятки раз более читаемо, чем то, что может нам предоставить Objective-C.

В Swift есть еще одна абсолютно нишевая штука, которая также пришла из функциональных языков программирования – function currying:

func add(a: Int)(b: Int) -> Int {
	return a + b
}

let foo = add(5)(b: 3) // 8

let add5 = add(5) // (Int) -> Int
let bar = add(b: 3) // 8

Мы видим, что у нас есть функция add с таким хитрым объявлением: две пары скобок с параметрами вместо одной. Это дает нам возможность либо вызвать эту функцию почти что как обычную и получить результат 8, либо вызвать ее с одним параметром. Во втором случае происходит магия: на выходе мы получаем функцию, которая принимает Int и возвращает тоже Int, т.е. мы частично применили нашу функцию add к пятерке. Соответственно, мы можем потом применить функцию add5 с тройкой и получить восьмерку.

Как я уже говорил, препроцессор отсутствует, поэтому даже реализовать assert – нетривиальная штука. Предположим, что у нас есть задача написать какой-нибудь свой assert. На дебаг мы его можем проверить, но чтобы код, который в ассерте не выполнится, мы должны передать его как замыкание. Т.е. мы видим, что у нас 5 % 2 в фигурных скобках. В терминологии Objective-C – это блок.

func assert(condition:() -> Bool, message: String) {
	#if DEBUG
		if !condition() { println(message) }
	#endif
} 

assert({5 % 2 == 0}, "5 isn't an even number.")

Понятно, что ассерты так использовать никто не будет. Поэтому в Swift есть автоматические замыкания. В декларации метода мы видим @autoclosure, соответственно, первый аргумент оборачивается в замыкание, и фигурные скобки можно не писать.

func assert(condition: @auto_closure () -> Bool, message: String) {
	#if DEBUG
		if !condition() { println(message) }
	#endif
} 

assert(5 % 2 == 0, "5 isn't an even number.")

Еще одна незадокументированная, но очень полезная вещь – явное преобразование типов. Swift – типизированный язык, поэтому как в Objective-C совать объекты с id-типом мы не можем. Поэтому рассмотрим следующий пример. Допустим у меня есть структура Box, которая в получает при инициализации какое-то значение, изменять которо нельзя. И у нас есть запакованный Int – единица.

struct Box<T> {
	let _value : T

	init (_ value: T) {
		_value = value
	}
}

let boxedInt = Box(1) //Box<Int>

Также у нас есть функция, которая принимает на вход Int. Соответственно, boxedInt мы туда передать не можем, т.к. компилятор нам скажет, что Box не конвертируется в Int. Умельцы немного распотрошили внутренности свифта и нашли функцию, позволяющую конвертировать тип Box в значение, которое он в себе скрывает:

extension Box {
	@conversion Func __conversion() -> T {
		return _value
	}
}

foo(boxedInt) //success

Статическая типизация языка также не позволяет нам бегать по классу и подменять методы, как это можно было делать в Objective-C. Из того, что есть сейчас, мы можем только получить список свойств объекта и вывести их значения на данный момент. Т.е. информации о методах мы получить не можем.

struct Foo {
	var str = "Apple"
	let int = 13

	func foo() { }
}


reflect(Foo()).count			// 2

reflect(Foo())[0].0				// "str"
reflect(Foo())[0].1summary		// "Apple"

Из свифта можно напрямую вызывать С-код. Эта фича не отражена в документации, но может быть полезна.

@asmname("my_c_func")
func my_c_func(UInt64, CMutablePointer<UInt64>) -> CInt;

Swift, конечно, компилируемый язык, но это не мешает ему поддерживать скрипты. Во-первых, есть интерактивная среда выполнения, запускаемая при помощи команды xcrun swift. Кроме того, можно писать скрипты не на привычных скриптовых языках, а непосредственно на Swift. Запускаются они при помощи команды xcrun -i 'file.swift'.

Напоследок я расскажу о репозиториях, на которые стоит посмотреть:
  • BDD Testing framework: Quick. Это первое, чего всем не хватало. Фреймворк активно развивается, постоянно добавляются новые матчеры.
  • Reactive programming: RXSwift. Это переосмысление ReactiveCocoa при помощи конструкций, предоставляемых свифтом.
  • Model mapping: Crust. Аналог Mantle для Swift. Позволяет мапить JSON-объекты в объекты свифта. Используется многие интересные хаки, которые могут быть полезны в разработке.
  • Handy JSON processing: SwiftyJSON. Это очень небольшая библиотека, буквально 200 строк. Но она демонстрирует всю мощь перечислений.
Автор: @elcoyot
Яндекс
рейтинг 459,86

Комментарии (28)

  • +2
    количество готовых программ на этом языке хоть за 5 перевалило?
    • +3
      Кажется, рисков, что на Свифте не будет программ, не существует — всё-таки, рынок софта под iOS очень большой.
    • +1
      О чем вопрос? Сейчас нельзя даже запостить написанную программу на Свифе в стор.
    • 0
      Так не было еще официального релиза.
    • 0
      На гитхабе сейчас 2696 репозиториев.

      Видимо, да, перевалило. (Не знаю, сколько их было на момент написания комментария.)
  • +5
    а что он крутится все время на стуле, все таки презентация: все дела…
  • –1
    Не знаю, как для остальных, но для меня (я привык работать с С++ и Obj-C, на Swift только начал посматривать), вот это выглядит не очень:
    let tree: Tree<Int> = .Node(.Leaf(1), .Leaf(1))
    Может быть это дело привычки, но синтаксис жутковат.
  • +2
    Еще один бросился в погоню за C#
    • –1
      И где в этом C# алгебраические типы данных?
  • 0
    Насчет Optional — это же частный случай алгебраических типов данных. Нам что, не дадут ими попользоваться в полную силу?
    • +1
      дадут, если пофиксят рекурсивные enumerations
      • 0
        Ну вообще определять алгебраический тип через такое «перечисление на стероидах» — это что-то довольно странное на мой взгляд.

        Не то, чтобы я был сильно против, но уж другое ключевое слово подобрать можно было.
        • 0
          Не то чтобы я с вами не согласен, но авторы языка тоже вроде люди умные, возможно не видят в отдельной концепции смысла.
        • 0
          Это вполне нормальный подход для людей, которые будут приходить с плюсов и Java (особенно в последней, где enum'ы тоже имеют методы etc).
  • +5
    После первоначального восхищения свифтом пришло горькое понимание что мы получили гибрид C++/ObjC/функциональщины.
    Зачем было вырезать динамизм например?
    Пока не вижу сильных преимуществ перед С++
    • 0
      «Динамизм» — это убийственно для скорости и сложнее отлавливать ошибки. Разве нет? Какие в нём вообще плюсы?
      • 0
        Например — у меня в проектах есть пара мест где без этого не обойтись.
        Банальный пример — у Apple кастомизация системных гуи элементов хромает на обе ноги.
        У тебя есть UISearchBar но изменить простые вещи как цвет текста или добавить делегата на внутренний UITextField нельзя. И Apple это даже не хочет как то исправлять.
        Без хаков на основе динамизма я без поняти как можно было бы делать глубокую кастомизацию — когда тебе позарез нужен системный элемент.
        Динамизм помогает исправлять косяки Apple — как на свифте их можно будет исправлять?
        Ждать с моря погоды?
        • +2
          Т.е. Вы со сути перехватываете и подменяете вызовы между этим контролом и системой?

          Интересно, а Apple пропускает приложения с таким фривольным (с точки зрения самой Apple) отношением к системным контролам? Т.е. я полагаю. что у них такая политика просто, что вам это не нужно.

          Хорошая новость, что ObjC никто пока не отменял и отменять не собирается.
          • +1
            Ага + в этом и мякота Objective-c -что можно заменить хоть реализацию всех системных объектов.
            Вообщем стрелять из гаубицы себе в ногу ядерными зарядами.
            в ObjC гораздо сложнее что то запретить чем разрешить — и Apple видимо надоело что все кому не лень ползают в нутрах их драгоценных фреймворках.

            ObjC никто не отменял — НО
            1) Теперь вместо связки Objc+ C++ в серьезных проектах будет Swift + Objc+ C++ — ха? теперь проще стало да?
            2) Apple вместо допиливания инструмента начнет его пропихивать везде где можно.
            Примерно как с Core Data — интеграция и прочия няшности это конечно прекрасно но например отсутствие возможности сделать выборку по transient атрибутам убивает смысл использования в тяжелых проектах.

            Короче опять традиция Apple сделать так что ЛГБТ сообщества поперхнуться

            • 0
              товарищ Латнер писал на девфоруме, что интеропу с C++ быть, сейчас все уперлось в реализацию Clang Modules для C++ (с его слов).

              И все-таки C++-код юзает очень малый процент iOS-приложений (в играх этот процент сильно выше, наверное, да).
  • 0
    Кстати, насчет немутабельных массивов и возможности их изменений все как-то странно, ведь в документации написано что это таки фича, а не баг

    «Immutability has a slightly different meaning for arrays, however. You are still not allowed to perform any action that has the potential to change the size of an immutable array, but you are allowed to set a new value for an existing index in the array. This enables Swift’s Array type to provide optimal performance for array operations when the size of an array is fixed.»

    Отрывок из книги: Inc, Apple. «The Swift Programming Language.» Apple Inc., 2014-05-27T07:00:00Z. iBooks.
    Этот материал может быть защищен авторским правом.

    Посмотрите эту книгу в iBooks Store: itunes.apple.com/WebObjects/MZStore.woa/wa/viewBook?id=881256329
    • 0
      Один из авторов языка говорит на дев-форуме, что это баг devforums.apple.com/message/971330#971330 (я упоминал это в презентации)
      • 0
        Да, я это понял. по этому и написал выше что история какая-то странная. еще когда читал книгу, думал про себя, мол странно это все, ну ок, может там все так и задумано, даже объяснение есть
        • +3
          Они похоже сами ещё не решили, задумано так или нет )
    • 0
      update: прилетела beta3 а там now a 'let' array is completely immutable, and a 'var' array is completely mutable
      adcdownload.apple.com//Developer_Tools/xcode_6_beta_3_lpw27r/xcode_6_beta_3_release_notes_.pdf
  • +2
    Добавьте публикацию в хаб Swift*.
    • 0
      Done.
  • 0
    А вот некоторые моменты, которые кому-то не нравятся
    itdumka.com.ua/index.php?cmd=shownode&node=41
    itdumka.com.ua/index.php?cmd=shownode&node=40

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.

Самое читаемое Разработка