Можно добавлять расширения к существующим типам объектов Swift с использованием расширений, как описано в спецификация языка.
В результате можно создавать расширения, такие как:
extension String {
var utf8data:NSData {
return self.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
}
}
Однако, какая лучшая практика именования для исходных файлов Swift, содержащих такие расширения?
В прошлом соглашение заключалось в использовании extendedtype+categoryname.m
для Objective-C
типа, как описано в руководстве Objective-C. Но пример Swift не имеет названия категории, и вызов его String.swift
кажется нецелесообразным.
Итак, вопрос: учитывая вышеприведенное расширение String
, какой должен быть вызван быстрый файл-источник?
Большинство примеров, которые я видел, имитируют подход Objective-C. Вышеприведенный пример выше:
String+UTF8Data.swift
Преимущества заключаются в том, что соглашение об именах позволяет легко понять, что это расширение и какой класс расширяется.
Проблема с использованием Extensions.swift
или даже StringExtensions.swift
заключается в том, что невозможно определить цель файла по его имени, не глядя на его содержимое.
Использование подхода xxxable.swift
, используемого Java, хорошо подходит для протоколов или расширений, которые определяют методы. Но опять же, пример выше определяет атрибут так, что UTF8Dataable.swift
не делает много грамматического смысла.
Нет соглашения о быстрой встрече. Держите это просто:
StringExtensions.swift
Я создаю один файл для каждого класса, который я расширяю. Если вы используете один файл для всех расширений, он быстро превратится в джунгли.
Мое предпочтение заключается в том, чтобы поставить "Extension_" в начале файла. (Я поместил все связанные расширения в один и тот же файл.)
Таким образом, все файлы расширения вместе, в алфавитном порядке, находятся в моем каталоге приложений и навигаторе Xcode. Конечно, в навигаторе я тоже могу их сгруппировать.
Итак, расширение, связанное со строкой, должно войти в Extension_String.swift
Я предпочитаю StringExtensions.swift
, пока не добавлю слишком много вещей, чтобы разбить файл на что-то вроде String+utf8Data.swift
и String+Encrypt.swift
.
Еще одна вещь, чтобы объединить похожие файлы в один, сделает ваше здание более быстрым. См. Optimizing-Swift-Build-Times
Если у вас есть согласованный по команде набор общих и разных улучшений, объединив их вместе как Extensions.swift, он будет использоваться как решение первого уровня Keep-It-Simple. Однако по мере того, как ваша сложность возрастает или расширяются расширения, требуется иерархия для инкапсуляции сложности. В таких обстоятельствах я рекомендую следующую практику с примером.
У меня был класс, который говорил с моим back-end, называемым Server
. Он стал расти больше, чтобы охватить два разных целевых приложения. Некоторые люди любят большой файл, но просто логически разделяются с расширениями. Мое предпочтение заключается в том, чтобы держать каждый файл относительно коротким, поэтому я выбрал следующее решение. Server
первоначально соответствовал CloudAdapterProtocol
и реализовал все его методы. То, что я сделал, это превратить протокол в иерархию, обратившись к подчиненным протоколам:
protocol CloudAdapterProtocol: ReggyCloudProtocol, ProReggyCloudProtocol {
var server: CloudServer {
get set
}
func getServerApiVersion(handler: @escaping (String?, Error?) -> Swift.Void)
}
В Server.swift
у меня есть
import Foundation
import UIKit
import Alamofire
import AlamofireImage
class Server: CloudAdapterProtocol {
.
.
func getServerApiVersion(handler: @escaping (String?, Error?) -> Swift.Void) {
.
.
}
Server.swift
затем просто реализует API-интерфейс основного сервера для настройки сервера и получения версии API. Реальная работа делится на два файла:
Server_ReggyCloudProtocol.swift
Server_ProReggyCloudProtocol.swift
Они реализуют соответствующие протоколы.
Это означает, что вам нужно иметь декларации импорта в других файлах (для Alamofire в этом примере), но это чистое решение с точки зрения разделения интерфейсов на мой взгляд.
Я думаю, что этот подход работает одинаково с внешними заданными классами, а также с вашими собственными.
ClassName+ExtensionName
, и которые, как я вижу, слишком много людей все еще используют. Кроме того, я нахожу это неуклюжим вместо того, чтобы просто определять классы и расширения вместе или давать файлу лучшее имя, напримерFooAbleTypes
и определять экземпляры в совокупности.