Dokumentacja wspomina tylko o typach zagnieżdżonych, ale nie jest jasne, czy można ich używać jako przestrzeni nazw. Nie znalazłem żadnej wyraźnej wzmianki o przestrzeniach nazw.
Dokumentacja wspomina tylko o typach zagnieżdżonych, ale nie jest jasne, czy można ich używać jako przestrzeni nazw. Nie znalazłem żadnej wyraźnej wzmianki o przestrzeniach nazw.
Odpowiedzi:
Odpowiedział SevenTenEleven na forum deweloperów Apple :
Przestrzenie nazw nie są przypisane do poszczególnych plików; są dla celu (na podstawie ustawienia kompilacji „Nazwa modułu produktu”). Więc skończyłbyś z czymś takim:
import FrameworkA import FrameworkB FrameworkA.foo()
Wszystkie deklaracje Swift są uważane za część jakiegoś modułu, więc nawet gdy powiesz „
NSLog
” (tak, nadal istnieje), otrzymujesz to, o czym Swift myśli jako „Foundation.NSLog
”.
Również Chris Lattner napisał na Twitterze o przestrzeni nazw .
Przestrzenie nazw są niejawne w Swift, wszystkie klasy (itp.) Są niejawnie określane przez moduł (cel Xcode), w którym się znajdują. Nie są potrzebne przedrostki klas
Wydaje się, że bardzo różni się to, o czym myślałem.
forums.developer.apple.com
witryny forów.
Przestrzenie nazw Swifta opisałbym jako aspiracyjne; otrzymała wiele reklam, które nie odpowiadają żadnej znaczącej rzeczywistości w terenie.
Na przykład filmy WWDC stwierdzają, że jeśli importowana struktura ma klasę MyClass, a kod ma klasę MyClass, nazwy te nie powodują konfliktu, ponieważ „zniekształcanie nazw” nadaje im różne nazwy wewnętrzne. W rzeczywistości jednak powodują konflikty w tym sensie, że wygrywa MyClass twojego własnego kodu i nie możesz określić "Nie, nie, mam na myśli MyClass w frameworku" - stwierdzenie TheFramework.MyClass
nie działa (kompilator wie, co masz na myśli , ale mówi, że nie może znaleźć takiej klasy we frameworku).
Z mojego doświadczenia wynika, że w związku z tym Swift nie jest w najmniejszym stopniu przestrzenią nazw. Zmieniając jedną z moich aplikacji z Objective-C na Swift, stworzyłem wbudowany framework, ponieważ było to tak łatwe i fajne do wykonania. Importowanie frameworka importuje jednak wszystkie rzeczy Swift we frameworku - więc presto, po raz kolejny jest tylko jedna przestrzeń nazw i jest globalna. I nie ma nagłówków Swift, więc nie możesz ukryć żadnych nazw.
EDYCJA: W seed 3 ta funkcja zaczyna być teraz dostępna online, w następującym sensie: jeśli twój główny kod zawiera MyClass, a twój framework MyFramework zawiera MyClass, pierwsza domyślnie przesłania drugą, ale możesz dotrzeć do tego we frameworku używając składni MyFramework.MyClass
. Tak więc w rzeczywistości mamy podstawy odrębnej przestrzeni nazw!
EDYCJA 2: W seed 4 mamy teraz kontrolę dostępu! Ponadto w jednej z moich aplikacji mam osadzony framework i oczywiście wszystko było domyślnie ukryte i musiałem jawnie ujawnić wszystkie bity publicznego API. To duża poprawa.
Foundation.NSArray
.
Robiąc z tym pewne eksperymenty, skończyło się na utworzeniu tych klas z "przestrzenią nazw" w ich własnych plikach poprzez rozszerzenie "pakietu" głównego. Nie jestem pewien, czy jest to sprzeczne z najlepszymi praktykami lub czy ma jakieś konsekwencje, o których jestem świadomy (?)
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
}
}
}
Edytować:
Właśnie się dowiedziałem, że tworzenie „podpakietów” w powyższym kodzie nie zadziała, jeśli używasz oddzielnych plików. Może ktoś podpowie, dlaczego tak się dzieje?
Dodanie następujących plików do powyższego:
PackageOneSubPackage.swift
import Foundation
extension PackageOne {
struct SubPackage {
}
}
PackageOneSubPackageClass.swift
extension PackageOne.SubPackage {
class Class {
var name: String
init(name:String) {
self.name = name
}
}
}
Zgłasza błąd kompilatora: „Pakiet podrzędny” nie jest typem elementu członkowskiego „PakietOne”
Jeśli przeniosę kod z PackageOneSubPackageClass.swift do PackageOneSubPackage.swift, to działa. Ktoś?
Edycja 2:
Bawiąc się tym nadal i odkryłem (w Xcode 6.1 beta 2), że definiując pakiety w jednym pliku, można je rozszerzyć w oddzielnych plikach:
public struct Package {
public struct SubPackage {
public struct SubPackageOne {
}
public struct SubPackageTwo {
}
}
}
Oto moje pliki w skrócie: https://gist.github.com/mikajauhonen/d4b3e517122ad6a132b8
Uważam, że osiąga się to za pomocą:
struct Foo
{
class Bar
{
}
}
Następnie można uzyskać do niego dostęp za pomocą:
var dds = Foo.Bar();
enum
, a nie a struct
, więc nie możesz utworzyć instancji Foo
.
Swift używa modułów podobnie jak w Pythonie (patrz tutaj i tutaj ) i jak zasugerował @Kevin Sylvestre, możesz również użyć zagnieżdżonych typów jako przestrzeni nazw.
Aby rozszerzyć odpowiedź @Daniel A. White, w WWDC rozmawiali o modułach w bardzo krótkim czasie.
Tutaj również wyjaśniono:
Wnioskowane typy sprawiają, że kod jest czystszy i mniej podatny na błędy, podczas gdy moduły eliminują nagłówki i udostępniają przestrzenie nazw.
Przestrzenie nazw są przydatne, gdy trzeba zdefiniować klasę o takiej samej nazwie jak klasa w istniejącej strukturze.
Załóżmy, że Twoja aplikacja ma
MyApp
nazwę i musisz zadeklarować swoją niestandardowąUICollectionViewController
.
Nie musisz dodawać przedrostków i podklas w ten sposób:
class MAUICollectionViewController: UICollectionViewController {}
Zrób to tak:
class UICollectionViewController {} //no error "invalid redeclaration o..."
Czemu? . Ponieważ to, co zadeklarowałeś, jest zadeklarowane w bieżącym module , który jest twoim aktualnym celem . A UICollectionViewController
from UIKit
jest zadeklarowany w UIKit
module.
Jak z niego korzystać w ramach obecnego modułu?
var customController = UICollectionViewController() //your custom class
var uikitController = UIKit.UICollectionViewController() //class from UIKit
Jak odróżnić je od innego modułu?
var customController = MyApp.UICollectionViewController() //your custom class
var uikitController = UIKit.UICollectionViewController() //class from UIKit
Możesz użyć extension
wspomnianego struct
podejścia do przestrzeni nazw bez konieczności wcięcia całego kodu w prawo. Byłem bawiąc się tym trochę i nie jestem pewien, czy tam w miarę tworzenia Controllers
i Views
nazw, jak w poniższym przykładzie, ale nie pokazują, jak daleko może pójść:
Profile.swift :
// Define the namespaces
struct Profiles {
struct Views {}
struct ViewControllers {}
}
Profile / 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
}
}
Profile / Views / Edit.swift
extension Profiles.Views {
class Edit: UIView {}
}
extension Profiles.Views.Edit {
override func drawRect(rect: CGRect) {
// Do some stuff
}
}
Nie używałem tego w aplikacji, ponieważ nie potrzebowałem jeszcze tego poziomu separacji, ale myślę, że to ciekawy pomysł. Eliminuje to potrzebę stosowania nawet sufiksów klas, takich jak wszechobecny sufiks * ViewController, który jest irytująco długi.
Jednak nie skraca niczego, gdy jest przywoływany, na przykład w parametrach metody, takich jak:
class MyClass {
func doSomethingWith(viewController: Profiles.ViewControllers.Edit) {
// secret sauce
}
}
Jeśli ktoś był ciekawy, od 10 czerwca 2014 r. Jest to znany błąd w Swift:
Od SevenTenEleven
„Znany błąd, przepraszam! Rdar: // problem / 17127940 Kwalifikowanie typów Swift na podstawie nazwy modułu nie działa.”