Swift'te Ad Alanları nasıl kullanılır?


144

Dokümantasyon sadece iç içe tiplerden bahsediyor, ancak isim alanı olarak kullanılıp kullanılamayacakları belli değil. İsim alanlarından açıkça bahsetmedim.


Onların iBook hızlı bir Ctrl-F arama hiçbir ad alanı örnekleri göstermez ... bu yüzden hayır ile gidiyorum?
Justin Niessner

1
Bu sorunun neden kapalı olduğunu bilmiyorum. Swift simgesinin sol tarafındaki
açılışta

Bu konuda hiçbir bilgi bulamadım, Google beni bu soruya yönlendirdi :). Belki WWDC oturumlarından biri buna biraz daha ışık tutacaktır.
Zyphrax

Ayrıca WWDC'de birisinin güzel bir açıklama bulmasını bekliyorum.
eonil

Eonil'in cevabı doğrudur. Sınıflarınızı ayırmak için Xcode'daki modülleri kullanırsınız.
Zyphrax

Yanıtlar:


113

Tarafından Cevaplanan SevenTenEleven içinde Apple dev forumun :

Ad alanları dosya başına değildir; bunlar hedef başınadır ("Ürün Modülü Adı" oluşturma ayarını temel alır). Böylece şöyle bir şey elde edersiniz:

import FrameworkA
import FrameworkB

FrameworkA.foo()

Tüm Swift bildirimleri bazı modüllerin bir parçası olarak kabul edilir, bu nedenle " NSLog" (evet, hala var) derken Swift'in " Foundation.NSLog" olarak düşündüğünü görürsünüz .

Ayrıca Chris Lattner isim boşluğunu tweetledi .

Ad boşluğu Swift'te örtüktür, tüm sınıflar (vb.) İçinde bulundukları modül (Xcode hedefi) tarafından dolaylı olarak kapsamlandırılır. Sınıf öneklerine gerek yoktur

Düşündüğümden çok farklı görünüyor.


6
Apple Dev forumları ... Orada inanamayacağınız kadar çok yabani ot gördüm!
Nicolas Miari

1
Apple geliştirici forumlarına bağlantı kesildi ve Apple bu konuyu forums.developer.apple.commaalesef yeni forumlar sitesine aktarmadı.
Dai

2
@Dai, bu nedenle Soru-Cevap için Apple forumlarından kaçınmalıyız ... Ancak çekirdek geliştirici ekip üyeleri SO'ya pek önem vermiyor gibi görünüyor. Ne trajedi.
eonil

1
tumbleweed ile ne demek istiyorsun?
Alexander Mills

148

Swift'in ad boşluğunu aspirasyon olarak tarif ederdim; yerdeki anlamlı gerçekliğe karşılık gelmeyen birçok reklam verildi.

Örneğin, WWDC videoları içe aktardığınız bir çerçevede bir Sınıf MyClass varsa ve kodunuzda bir Sınıf MyClass varsa, "ad yönetimi" onlara farklı dahili adlar verdiğinden, bu adlar çakışmaz. Gerçekte, ancak, bunu kendi kodun Sınıfım kazanç ve belirleyemezsiniz "Hayır hayır, ben çerçevesinde Sınıfım demek" anlamında, çatışma - diyerek TheFramework.MyClassdeğil işi (derleyici ne demek istediğini bilir yapar , ancak çerçevede böyle bir sınıf bulamadığını söylüyor).

Benim tecrübem, Swift'in en ufak bir isimde yer almaması. Uygulamalarımdan birini Objective-C'den Swift'e dönüştürürken gömülü bir çerçeve oluşturdum çünkü yapmak çok kolay ve havalıydı. Bununla birlikte, çerçeveyi içe aktarmak, çerçevedeki tüm Swift öğelerini içe aktarır - bu yüzden presto, bir kez daha sadece bir ad alanı vardır ve küreseldir. Ve Swift üstbilgileri yok, bu yüzden herhangi bir ismi gizleyemezsiniz.

DÜZENLEME: 3. tohumda, bu özellik şu anda çevrimiçi olmaya başlıyor, aşağıdaki anlamda: ana kodunuz MyClass içeriyorsa ve çerçeveniz MyFramework MyClass içeriyorsa, ilki varsayılan olarak ikincisini gölgede bırakır, ancak çerçevede bu özelliğe erişebilirsiniz sözdizimini kullanarak MyFramework.MyClass. Böylece aslında farklı bir isim alanının ilkelerine sahibiz!

EDIT 2: Tohum 4'te artık erişim kontrollerimiz var! Ayrıca, uygulamalarımdan birinde gömülü bir çerçevem ​​var ve yeterince eminim, her şey varsayılan olarak gizlendi ve herkese açık API'nın tüm bitlerini açıkça ortaya koymak zorunda kaldım. Bu büyük bir gelişme.


4
Bu cevap için teşekkürler. Sadece Frameworks ile değil, aynı zamanda Standart Kütüphane ile de çalışır. Örneğin, Dizinin üzerine "yazabilirsiniz". Sonra "Array" kendi özel Array sınıfınızı ifade eder ve Standard Library's Array "Swift.Array" olarak kullanılabilir.
George

3
@George Ve benzer şekilde NSArray için; gölgede bırakırsanız, yine de olarak başvurabilirsiniz Foundation.NSArray.
mat

1
Bu yüzden betalardaki ad alanlarındaki düşünce tarihini sıralamak zorunda kalmadan: bu cevap şimdi nerede duruyor?
Dan Rosenstark

1
@Yar düzenlemelerde belirtildiği gibi. Modül adı, belirsizlik varsa isteğe bağlı bir ad alanıdır ve şimdi gizlilik vardır, böylece modül adları gösterilmedikçe gizlenir ve bir ad bir dosya ile sınırlandırılabilir.
matt

2
Bu beni uzun zamandır rahatsız ediyor, herhangi bir Swift projesinin Apple'ın iddia ettiği için bir önek kullanmaması gerekiyor, ancak şu anda erişim değiştiricilerle bile bir önek gerekli. Apple'ın çerçevesindeki paket veya özel sınıflarla çatışmayacak olsanız da, herkese açık olarak ilan edilen herhangi bir şey, örneğin String, tekrar beyan ederseniz veya herhangi bir yeni sınıf, tabii ki alışkanlığınız yoksa, kendinizinkini kullanır. ad alanı ile tüm sınıflara atıfta .... iyi değil imo.
Oscar Gomez

19

Bu konuda bazı deneyler yaparken kök "paket" genişleterek kendi dosyalarında bu "ad alanı" sınıfları oluşturmak sona erdi. Bunun en iyi uygulamalara aykırı olup olmadığından emin değilim ya da herhangi bir etkisi olup olmadığından emin değilim (?)

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
        }
    }
}

Düzenle:

Sadece yukarıdaki kodda "alt paketler" oluşturmanın ayrı dosyalar kullanırsanız işe yaramayacağını öğrendim. Belki birisi neden böyle olabileceğine dair ipucu verebilir?

Yukarıdakilere aşağıdaki dosyaları ekleme:

PackageOneSubPackage.swift

import Foundation

extension PackageOne {
    struct SubPackage {
    }
}

PackageOneSubPackageClass.swift

extension PackageOne.SubPackage {
    class Class {
        var name: String
        init(name:String) {
            self.name = name
        }
    }
}

Derleyici hatası veriyor: 'SubPackage', 'PackageOne' üyesi değil

Kodu PackageOneSubPackageClass.swift 'den PackageOneSubPackage.swift' e taşırsam çalışır. Kimse?

Düzenleme 2:

Bu hareketin etrafında dolaşmak ve (Xcode 6.1 beta 2'de) paketleri tek bir dosyada tanımlayarak ayrı dosyalarda genişletilebileceklerini keşfetti:

public struct Package {
  public struct SubPackage {
    public struct SubPackageOne {
    }
    public struct SubPackageTwo {
    }
  }
}

İşte dosyalarımın bir özeti: https://gist.github.com/mikajauhonen/d4b3e517122ad6a132b8


ilginç, testin nasıldı?
user2727195

2
"Test" ile ne demek istediğinizden emin değilim ama devam etti ve yukarıdaki tekniği kullanarak uygulamamı oluşturmaya başladım ve yukarıdaki girişime eklediğim uyarıyla şimdiye kadar iyi çalışıyor gibi görünüyor. Çoğunlukla yapıyorum çünkü kodumu diğer dillerde bu şekilde organize ediyordum ve daha fazla bilgiye sahip olan biri bana çok kötü bir fikir olana kadar kötü bir fikir olduğunu söylese minnettar olurum! :)
bWlrYWphdWhvbmVu

1
devam et ... istediğimiz bu ... iki farklı pakette aynı isim sınıfına sahip olabilmek ve buna göre (daha önemlisi farklı dosyalar) referans gösterebilmek ve eğer işe yaramazsa, bütün isim alanı fikri bir flop fikri ...
user2727195

Ad alanlarını hacklemenin bir yolu olarak "struct" kullanan herhangi bir yan etkisi var mı?
Alex Nolasco

Böyle bir performans konusunda karşılaştığım değil. Xcode (6.1 GM) bazı nadir durumlarda mevcut olmayan türlerden şikayetçi olmakla birlikte, bunun gibi kod yapılandırılmadığında da durumun böyle olabileceğine inanıyorum. Kısa bir süre önce test hedefime tüm dosyaları ekleyerek bir sorun çözdüm, bu hiç mantıklı değil ama sorunu çözdü. :)
bWlrYWphdWhvbmVu

12

Bunun kullanılarak elde edildiğine inanıyorum:

struct Foo
{
    class Bar
    {
    }
}

Ardından şunlara erişilebilir:

var dds = Foo.Bar();

1
Ad alanlarının yapılma şeklinden hala çok memnun değilim ... bir ad alanında on farklı sınıfım varsa ve ayrıca sınıfları kendi dosyalarında tutmayı tercih edersem, birini şişirmek istemiyorum dosya / struct ile tüm sınıflar, herhangi bir öneri Kevin.
user2727195

2
Neden paketleri dahil etmeyi düşünmediklerini merak ediyorum, isim alanlarına değil, ihtiyacımız olan şey bu, yani Java, C #, ActionScript gibi diğer üst düzey dillere bakın, hepsinin paketleri var, bu bağlamda ad alanları NS kullanmaktan farklı değil veya proje sınıflarınız için diğer önekler
user2727195

1
Yapılar ad alanlarını kesmek için bir yol olarak kullanmanın bilinmeyen sorunlara neden olup olmayacağını merak etmeye yardımcı olamaz.
Alex Nolasco

1
Bu güzel bir çözüm. Bu yaklaşımı kullanmayı denedim ama hemen durmak zorunda kaldım. Görünümle ilgili sınıflarımı adlandırmaya çalıştığımda (bir CustomTableViewCell diyelim), arayüz oluşturucusundaki otomatik tamamlama bunu önermedi. Bu yaklaşımı kullanmış olsaydım, görünüm için sınıf adını el ile kopyalayıp yapıştırmam gerekirdi.
ArG

1
Genellikle enuma değil, kullanırsınız struct, bu nedenle a'yı başlatamazsınız Foo.
Kevin

7

Swift, python'daki gibi modülleri kullanır ( buraya ve buraya bakın ) ve @Kevin Sylvestre'nin önerdiği gibi , iç içe türleri ad alanları olarak da kullanabilirsiniz .

Ve @Daniel A. White'ın cevabını genişletmek için WWDC'de hızlı bir şekilde modüller hakkında konuşuyorlardı.

Ayrıca burada açıklanmaktadır:

Çıkarılan türler kodu daha temiz ve hatalara daha az eğilimli hale getirirken, modüller başlıkları ortadan kaldırır ve ad alanları sağlar.


2
İkinci bağlantınızda belirtildiği gibi yapı gibi paketler arıyorum 6.4 Paketler (Python), iç içe tipler olarak ad alanları çok fazla dayanamıyor, 10 farklı sınıfta ve bir ad alanında farklı dosyalarda olsaydım ya da diyelim paket ???
user2727195

7
  • Ad alanları, mevcut çerçevede sınıfla aynı ada sahip bir sınıf tanımlamanız gerektiğinde yararlıdır .

  • Uygulamanızın MyAppadı olduğunu ve özelliğinizi beyan etmeniz gerektiğini varsayalım UICollectionViewController.

Bunun gibi ön ek ve alt sınıflar eklemenize gerek yoktur :

class MAUICollectionViewController: UICollectionViewController {}

Şöyle yapın:

class UICollectionViewController {} //no error "invalid redeclaration o..."

Neden? . Çünkü beyan ettiğiniz , mevcut hedefiniz olan geçerli modülde bildirilir . Ve gelen bildirilmiştir modülü.UICollectionViewControllerUIKitUIKit

Mevcut modülde nasıl kullanılır?

var customController = UICollectionViewController() //your custom class
var uikitController = UIKit.UICollectionViewController() //class from UIKit

Onları başka bir modülden nasıl ayırt edebilirim?

var customController = MyApp.UICollectionViewController() //your custom class
var uikitController = UIKit.UICollectionViewController() //class from UIKit

3

Sen kullanabilirsiniz extensionsözü kullanmak structsağa doğru tüm kodu girinti zorunda kalmadan ad alanı için yaklaşımını. Bununla biraz oynuyorum Controllersve Viewsaşağıdaki örnekte olduğu gibi oluşturma ve ad alanları kadar ileri gideceğimden emin değilim , ancak ne kadar ileri gidebileceğini gösteriyor:

Profiller. Kaydırma :

// Define the namespaces
struct Profiles {
  struct Views {}
  struct ViewControllers {}
}

Profiller / 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
  }
}

Profiller / Görüntüleme / Edit.swift

extension Profiles.Views {
  class Edit: UIView {}
}

extension Profiles.Views.Edit {
  override func drawRect(rect: CGRect) {
    // Do some stuff
  }
}

Henüz bu ayrılma düzeyine ihtiyaç duymadığım için bunu bir uygulamada kullanmadım ama bence ilginç bir fikir. Bu, rahatsız edici derecede uzun olan her yerde bulunan * ViewController soneki gibi sınıf eklerine bile olan ihtiyacı ortadan kaldırır.

Ancak, bu gibi yöntem parametrelerinde olduğu gibi referans alındığında hiçbir şeyi kısaltmaz:

class MyClass {
  func doSomethingWith(viewController: Profiles.ViewControllers.Edit) {
    // secret sauce
  }
}

2

Birisinin merak etmesi durumunda, 10 Haziran 2014'ten itibaren bu Swift'te bilinen bir hatadır:

Gönderen SevenTenEleven

"Bilinen bir hata, özür dilerim! Rdar: // problem / 17127940 Swift türlerini modül adlarına göre çalışmaz."


Aşağıdaki @ matt'in gönderisine göre, bu Swift'te şu anda bilinen bir hatadır.
Adam Venturella

Bu, şimdi Beta 3'te düzeltildi (7 Temmuz 2014'te yayınlandı)
Adam Venturella
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.