У документації згадуються лише вкладені типи, але незрозуміло, чи можна їх використовувати як простори імен. Я не знайшов явних згадок про простори імен.
У документації згадуються лише вкладені типи, але незрозуміло, чи можна їх використовувати як простори імен. Я не знайшов явних згадок про простори імен.
Відповіді:
Відповів SevenTenEleven на форумі Apple dev :
Простори імен не є файлами; вони на ціль (засновані на налаштуваннях "Назва модуля продукту"). Отже, ви закінчите щось подібне:
import FrameworkA import FrameworkB FrameworkA.foo()
Усі заяви Swift вважаються частиною якогось модуля, тому навіть коли ви говорите "
NSLog
" (так, він все ще існує), ви отримуєте те, що Swift вважає "Foundation.NSLog
".
Також Кріс Леттнер написав твіт щодо простору імен .
Простір імен неявний у Swift, усі класи (тощо) неявно охоплюються модулем (ціль Xcode), у якому вони перебувають. Не потрібні префікси класу
Здається, дуже відрізняється від того, про що я думав.
forums.developer.apple.com
, на жаль, не імпортувала цю тему на новий форум форумів.
Я б назвав простір імен Свіфт як прагнений; дано багато реклами, яка не відповідає жодній змістовної реальності на місцях.
Наприклад, у відеозаписах WWDC зазначено, що якщо в імпортній системі є клас MyClass, а у вашому коді - клас MyClass, ці назви не суперечать, оскільки "ім'я" керує іменами "дає їм різні внутрішні імена. Насправді, однак, вони роблять конфлікт, в тому сенсі , що MyClass виграє свій власний код, і ви не можете вказати «Ні , ні, я маю на увазі MyClass в рамках» - мовляв TheFramework.MyClass
не працює (компілятор знає , що ви маєте в виду , але він говорить, що не може знайти такий клас у рамках).
Мій досвід полягає в тому, що Свіфт не має найменшого простору. Перетворюючи одне з моїх додатків з Objective-C на Swift, я створив вбудований каркас, оскільки це було так просто і круто зробити. Імпортуючи рамку, проте, імпортує всі речі Swift у рамки - так що раніше, знову є лише один простір імен, і він є глобальним. І немає заголовків Swift, тому ви не можете приховати жодні імена.
EDIT: У насіннику 3 ця функція починає з’являтися в Інтернеті в такому сенсі: якщо ваш основний код містить MyClass, а ваш фреймворк MyFramework містить MyClass, колишній замовчує останній за замовчуванням, але ви можете дістати його в рамках за допомогою синтаксису MyFramework.MyClass
. Таким чином, ми фактично маємо зачатки чіткого простору імен!
EDIT 2: У насінні 4 тепер у нас є контроль доступу! Плюс до того, що в одному з моїх додатків я вбудований фреймворк і досить впевнений, що все було приховано за замовчуванням, і мені довелося відкрити всі біти публічного API. Це велике поліпшення.
Foundation.NSArray
.
Проводячи деякі експерименти з цим, я в кінцевому підсумку створив ці "простір" імен у власних файлах, розширивши кореневий "пакет". Не впевнений, чи це проти передового досвіду чи це має якісь наслідки, про які я знаю (?)
AppDelegate.swift
var n1 = PackageOne.Class(name: "Package 1 class")
var n2 = PackageTwo.Class(name: "Package 2 class")
println("Name 1: \(n1.name)")
println("Name 2: \(n2.name)")
PackageOne.swift
import Foundation
struct PackageOne {
}
PackageTwo.swift
import Foundation
struct PackageTwo {
}
PackageOneClass.swift
extension PackageOne {
class Class {
var name: String
init(name:String) {
self.name = name
}
}
}
PackageTwoClass.swift
extension PackageTwo {
class Class {
var name: String
init(name:String) {
self.name = name
}
}
}
Редагувати:
Щойно з'ясували, що створення "підпакетів" у наведеному вище коді не буде працювати, якщо використовувати окремі файли. Можливо, хтось може натякнути, чому це було б так?
Додавання до вищезазначених файлів:
PackageOneSubPackage.swift
import Foundation
extension PackageOne {
struct SubPackage {
}
}
PackageOneSubPackageClass.swift
extension PackageOne.SubPackage {
class Class {
var name: String
init(name:String) {
self.name = name
}
}
}
Помилка компілятора: "SubPackage" не є типом "PackageOne"
Якщо я переміщу код з PackageOneSubPackageClass.swift до PackageOneSubPackage.swift, він працює. Хтось?
Редагувати 2:
З цим все-таки обернувшись і з’ясувавши (у Xcode 6.1 beta 2), що, визначаючи пакунки в одному файлі, їх можна розширити в окремі файли:
public struct Package {
public struct SubPackage {
public struct SubPackageOne {
}
public struct SubPackageTwo {
}
}
}
Ось мої файли в суті: https://gist.github.com/mikajauhonen/d4b3e517122ad6a132b8
Я вважаю, що це досягається за допомогою:
struct Foo
{
class Bar
{
}
}
Тоді це можна отримати за допомогою:
var dds = Foo.Bar();
enum
, а не struct
, тому ви не можете створити інстанцію Foo
.
Swift використовує модулі, подібні до python (див. Тут і тут ), і як запропонував @Kevin Sylvestre, ви також можете використовувати вкладені типи як простори імен.
І щоб продовжити відповідь від @Daniel A. White, в WWDC вони швидко говорили про модулі.
Також тут пояснюється:
Зазначені типи роблять код чистішим та менш схильним до помилок, тоді як модулі усувають заголовки та надають простори імен.
Простори імен корисні, коли вам потрібно визначити клас з тим самим іменем, що і клас у існуючих рамках.
Припустимо, ваш додаток має
MyApp
ім’я, і вам потрібно оголосити свій звичайUICollectionViewController
.
Вам не потрібно таких префіксів і підкласів:
class MAUICollectionViewController: UICollectionViewController {}
Зробіть так:
class UICollectionViewController {} //no error "invalid redeclaration o..."
Чому? . Тому що те, що ви заявили, оголошено в поточному модулі , який є вашою поточною ціллю . І UICollectionViewController
від UIKit
оголошено в UIKit
модулі.
Як використовувати його в поточному модулі?
var customController = UICollectionViewController() //your custom class
var uikitController = UIKit.UICollectionViewController() //class from UIKit
Як відрізнити їх від іншого модуля?
var customController = MyApp.UICollectionViewController() //your custom class
var uikitController = UIKit.UICollectionViewController() //class from UIKit
Ви можете використовувати extension
згаданий struct
підхід для простору імен без відступу всього коду вправо. Я трохи бавився з цим, і не впевнений, що б пішов так, як створювати Controllers
і Views
простори імен, як у прикладі нижче, але він ілюструє, як далеко можна зайти:
Profiles.swift :
// Define the namespaces
struct Profiles {
struct Views {}
struct ViewControllers {}
}
Профілі / ViewControllers / Edit.swift
// Define your new class within its namespace
extension Profiles.ViewControllers {
class Edit: UIViewController {}
}
// Extend your new class to avoid the extra whitespace on the left
extension Profiles.ViewControllers.Edit {
override func viewDidLoad() {
// Do some stuff
}
}
Профілі / Перегляди / Редагувати
extension Profiles.Views {
class Edit: UIView {}
}
extension Profiles.Views.Edit {
override func drawRect(rect: CGRect) {
// Do some stuff
}
}
Я не використовував це в додатку, оскільки мені ще не потрібен цей рівень розділення, але я думаю, що це цікава ідея. Це знімає потребу в рівних суфіксах класу, таких як всюдисущий * суфікс ViewController, який досадно довгий.
Однак він не скорочує нічого, коли на нього посилається, наприклад, у таких параметрах методу:
class MyClass {
func doSomethingWith(viewController: Profiles.ViewControllers.Edit) {
// secret sauce
}
}
Якщо комусь було цікаво, станом на 10 червня 2014 року, це відома помилка у Свіфті:
Від SevenTenEleven
"Відома помилка, вибачте! Rdar: // проблема / 17127940 Кваліфікація типів Swift за назвою їх модуля не працює."