Подразделы:
- Strings (строки)
- Numbers (числа)
- Collection Classes (классы коллекций)
- Swift 2.0: Errors (Ошибки)
- Foundation Data Types (Типы данных foundation)
- Foundation Functions (функции Foundation)
- Core Foundation
- Unmanaged Objects (Неуправляемые объекты)
Существуют типы в Swift и Objective-C, которые являются взаимозаменяемыми (bridged). Например NSString и String, NSArray и Array
Strings (строки)
Везде где в API ожидается NSString мы можем подставлять Swift String, и наоборот. По факту, когда Swift импортирует Objective-C API он сам заменяет все вхождения NSString на String, при импорте swift в Objective-C наоборот String заменяется на NSString
Чтобы включить поддержку взаимозаменяемости строк нужно импортировать Foundation, это позволит нам использовать capitalizedString свойство доступное в NSString, но которого нет в Swift String
1 2 3 4 |
import Foundation let greeting = "hello, world!" let capitalizedGreeting = greeting.capitalizedString // capitalizedGreeting: String = Hello, World! |
Можно приводить к String с помощью as
1 2 3 4 5 |
import Foundation let myString: NSString = "123" if let integerValue = (myString as String).toInt() { println("\(myString) is the integer \(integerValue)") } |
Для локализации в Objective-C использовался набор макросов NSLocalizedString, NSLocalizedStringFromTable, NSLocalizedStringFromTableInBundle и NSLocalizedStringWithDefaultValue. В Swift их заменила единственная функция NSLocalizedString(key:tableName:bundle:value:comment:)
Numbers (числа)
Swift типы Int, UInt, Float, Double автоматически приводятся к Objective-C NSNumber (Но не в обратную сторону, если ожидается Int – нельзя подставить NSNumber, т.к. внутри может быть и Bool)
Collection Classes (классы коллекций)
Arrays (массивы)
Swift позволяет использовать взаимозаменяемо Array и NSArray.
Если тип массива в Objective-C был указан – то приводится к [ObjectType] (доступно только в Swift 2.0)
Если нет то к [AnyObject]
Массив [AnyObject] можно привести к конкретному типу, но без гарантий
1 2 3 4 |
let swiftArray = foundationArray as [AnyObject] if let downcastedSwiftArray = swiftArray as? [UIView] { // downcastedSwiftArray содержит только UIView объекты } |
В данном случае если хоть один элемент имеет тип отличный от UIView – downcastedSwiftArray будет присвоено Nil и код внутри скобок не отработает.
Но можно и делать и принудительное приведение
1 2 3 |
for aView in foundationArray as [UIView] { // aView is of type UIView } |
Но если есть элементы с типом отличным от UIView – вылетит ошибка.
При приведении swift массива к NSArray – элементы внутри должны быть совместимы с AnyObject.
Можно создавать NSArray с помощью обычного синтаксиса создания массивов
1 2 |
let schoolSupplies: NSArray = ["Pencil", "Eraser", "Notebook"] // schoolSupplies имеет тип NSArray и содержит объекты типа NSString |
Как и у строк при импорте API происходит замена Array на NSArray и наоборот в зависимости от направления импорта.
Sets (Наборы)
Swift позволяет использовать взаимозаменяемо Set и NSSet
Все один в один как у массивов – и приведение и создание и действия при импорте API. NSSet в Objective-C после swift 2.0 так же начали поддерживать Lightweight Generics
Dictionaries (словари)
Swift позволяет использовать взаимозаменяемо Dictionary и NSDictionary
1 |
NSDictionary<KeyType *, ValueType*>* -> [KeyType:ValueType] |
1 |
NSDictionary * -> [NSObject:AnyObject] |
И снова таки все остальное как у массивов
Errors (Ошибки) Swift 2.0
Swift позволяет использовать взаимозаменяемо ErrorType и NSError
Swift перечисление реализующее протокол ErrorType обозначенное с помощью @objc атрибута – сгенерирует как NS_ENUM определение, так и NSString константу для соответствующего домена ошибки в генерируемом заголовке (generated header)
Код
1 2 3 |
@objc public enum CustomError: Int, ErrorType { case A, B, C } |
Сгенерирует
1 2 3 4 5 6 7 8 |
// Project-Swift.h typedef SWIFT_ENUM(NSUInteger, CustomError) { CustomErrorA = 0, CustomErrorB = 1, CustomErrorC = 2, }; static NSString * const CustomErrorDomain = @"Project.CustomError"; |
Foundation Data Types (Типы данных foundation)
Swift предоставляет удобную прослойку для взаимодействия с типами данных в Foundation. Ею удобно пользоваться при работе с CGSize и CGPoint, к примеру создание
1 |
let size = NSSize(width: 20, height: 40) |
Или доступ к функциям
1 2 3 |
let rect = CGRect(x: 50, y: 50, width: 100, height: 100) let width = rect.width // эквивалент CGRectGetWidth(rect) let maxX = rect.maxY // эквивалент CGRectGetMaxY(rect) |
Чтобы узнать побольше – стоит поизучать такие типы данных с помощью ⌘+щелчок мышью по интересующему классу. К примеру щелчок по CGRect в swift файле вывел на файл определения, рядом же видно определение расширения. Приведу частично
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
extension CGRect { static var zeroRect: CGRect { get } static var nullRect: CGRect { get } static var infiniteRect: CGRect { get } init(x: CGFloat, y: CGFloat, width: CGFloat, height: CGFloat) init(x: Double, y: Double, width: Double, height: Double) init(x: Int, y: Int, width: Int, height: Int) var width: CGFloat { get } var height: CGFloat { get } var minX: CGFloat { get } var midX: CGFloat { get } var maxX: CGFloat { get } var minY: CGFloat { get } ///... и т.д. |
Swift делает взаимозаменяемыми NSUInteger и NSInteger к Int
Хотя если явно указать можно использовать и UInt
Foundation Functions (функции Foundation)
Для логирования в swift доступна функция NSLog
1 |
NSLog("%.7f", pi) // выведет "3.1415927" в консоль |
Так же доступна функция print(_:)
Вместо NSAssert нужно использовать assert
Core Foundation
Core Foundation типы автоматически импортируются как полноценные swift классы. Swift автоматически управляет памятью этих объектов, включая те что вы создали сами.
При использовании Core Foundation типов компилятор отрезает префикс Ref, т.к. все типы в swift – ссылочного типа. Но CFTypeRef становится AnyObject, а не CFType
Все Core Foundation объекты полученные из размеченных Apple’ом API получают автоматическое управление памятью, больше нет нужды вызывать функции CFRetain, CFRelease или CFAutorelease
Если мы написали собственную C функцию или Objective-C метод, возвращающие Core Foundation объект – нужно их пометить макросами CF_RETURNS_RETAINED или CF_RETURNS_NOT_RETAINED
Unmanaged Objects (Неуправляемые объекты)
Когда Swift импортирует API, которые не были размечены макросами управления памяти – компилятор не может автоматически управлять памятью для возвращенных такими функциями/методами Core Foundation объектов.
Возьмем для примера неразмеченную C функцию
1 |
CFStringRef StringByAddingTwoStrings(CFStringRef string1, CFStringRef string2) |
Swift ее импортирует как
1 |
func StringByAddingTwoStrings(CFString!, CFString!) -> Unmanaged<CFString>! |
Как только мы получаем неуправляемый объект мы должны немедленно конвертировать его в управляемый до начала работы с ним.
Структура Unmanaged
– takeUnretainedValue() для получения оригинального объекта для которого не был вызван retain
– takeRetainedValue() для получения оригинального объекта для которого был вызван retain
К примеру предположим, что функция StringByAddingTwoStrings возвращает not retained CFString объект. Для работы нужно вызвать на нем takeUnretainedValue
1 |
let memoryManagedResult = StringByAddingTwoStrings(str1, str2).takeUnretainedValue() |
Хотя мы можем вызывать retain(), release() и autorelease() методы на неуправляемых объектах напрямую – делать это крайне не рекомендуется