Làm cách nào để sử dụng Không gian tên trong Swift?


144

Tài liệu này chỉ đề cập đến các kiểu lồng nhau, nhưng không rõ liệu chúng có thể được sử dụng làm không gian tên hay không. Tôi không tìm thấy bất kỳ đề cập rõ ràng về không gian tên.


Một tìm kiếm Ctrl-F nhanh chóng trên iBook của họ cho thấy không có trường hợp nào về không gian tên ... vì vậy tôi sẽ không có?
Justin Niessner

1
Tôi không biết tại sao câu hỏi này được đóng lại. Tôi đã thấy không gian tên trên bài phát biểu ở phía bên trái của biểu tượng Swift và tôi vẫn không thể tìm thấy bất kỳ đề cập nào từ tài liệu này ...
eonil

Tôi không thể tìm thấy bất kỳ thông tin nào về điều này, Google đã dẫn tôi đến câu hỏi này :). Có lẽ một trong những phiên WWDC sẽ làm sáng tỏ hơn một chút về điều này.
Zyphrax

Tôi cũng đang chờ ai đó trong WWDC đưa ra lời giải thích hay.
eonil

Câu trả lời của Eonil là chính xác. Bạn sử dụng các mô-đun trong Xcode để phân tách các lớp của bạn.
Zyphrax

Câu trả lời:


113

Đã được trả lời bởi SevenTenEleven trong diễn đàn nhà phát triển của Apple :

Không gian tên không phải là mỗi tệp; chúng theo từng mục tiêu (dựa trên cài đặt xây dựng "Tên mô-đun sản phẩm"). Vì vậy, bạn sẽ kết thúc với một cái gì đó như thế này:

import FrameworkA
import FrameworkB

FrameworkA.foo()

Tất cả các khai báo Swift được coi là một phần của một số mô-đun, vì vậy ngay cả khi bạn nói " NSLog" (vâng, nó vẫn tồn tại) bạn sẽ nhận được những gì Swift nghĩ là " Foundation.NSLog".

Ngoài ra Chris Lattner đã tweet về không gian tên .

Không gian tên được ẩn trong Swift, tất cả các lớp (v.v.) được ẩn trong phạm vi bởi mô-đun (mục tiêu Xcode) mà chúng đang ở. Không cần tiền tố lớp

Có vẻ rất khác những gì tôi đã nghĩ.


6
Diễn đàn Apple Dev ... Tôi đã thấy rất nhiều tumbleweed ở đó bạn sẽ không tin!
Nicolas Miari

1
Liên kết đến các diễn đàn nhà phát triển của Apple hiện đã bị hỏng và forums.developer.apple.comthật không may , Apple đã không nhập chủ đề đó vào trang diễn đàn mới .
Đại

2
@Dai Có vẻ như đó là lý do tại sao chúng ta nên tránh các diễn đàn của Apple để hỏi đáp ... Nhưng các thành viên nhóm phát triển cốt lõi dường như không quan tâm nhiều đến SO. Thật là một thảm kịch.
eonil

1
ý bạn là gì bởi tumbleweed?
Alexander Mills

148

Tôi sẽ mô tả không gian tên của Swift là khát vọng; nó đã được cung cấp rất nhiều quảng cáo không tương ứng với bất kỳ thực tế có ý nghĩa nào.

Ví dụ: các video WWDC nói rằng nếu một khung bạn đang nhập có một lớp MyClass và mã của bạn có một lớp MyClass, các tên đó không xung đột vì "xáo trộn tên" cung cấp cho chúng các tên nội bộ khác nhau. Trên thực tế, tuy nhiên, họ làm xung đột, theo nghĩa là chiến thắng MyClass mã riêng của bạn, và bạn không thể xác định "Không không, tôi có nghĩa là MyClass trong khuôn khổ" - nóiTheFramework.MyClass không hoạt động (trình biên dịch biết ý của bạn là gì , nhưng nó nói rằng nó không thể tìm thấy một lớp như vậy trong khung).

Kinh nghiệm của tôi là Swift do đó không được đặt tên trong một chút. Khi chuyển một trong những ứng dụng của tôi từ Objective-C sang Swift, tôi đã tạo ra một khung nhúng vì nó rất dễ thực hiện. Tuy nhiên, nhập khung, nhập tất cả nội dung Swift trong khung - vì vậy, một lần nữa, chỉ có một không gian tên và nó là toàn cầu. Và không có tiêu đề Swift để bạn không thể ẩn bất kỳ tên nào.

EDIT: Trong seed 3, tính năng này hiện đang bắt đầu xuất hiện trực tuyến, theo nghĩa sau: nếu mã chính của bạn chứa MyClass và khung của bạn MyFramework chứa MyClass, cái trước sẽ làm lu mờ cái sau theo mặc định, nhưng bạn có thể tiếp cận cái trong khung bằng cách sử dụng cú pháp MyFramework.MyClass. Vì vậy, trên thực tế chúng ta có những sơ hở của một không gian tên riêng biệt!

EDIT 2: Trong hạt giống 4, bây giờ chúng ta có các điều khiển truy cập! Thêm vào đó, trong một trong những ứng dụng của tôi, tôi có một khung nhúng và chắc chắn, mọi thứ đều được ẩn theo mặc định và tôi phải phơi bày tất cả các bit của API công khai một cách rõ ràng. Đây là một cải tiến lớn.


4
Cảm ơn câu trả lời này. Nó hoạt động không chỉ với các Framework mà còn với Thư viện chuẩn. Bạn có thể "ghi đè" Array chẳng hạn. Sau đó, "Mảng" đề cập đến lớp Mảng tùy chỉnh của riêng bạn và Mảng Thư viện Chuẩn có sẵn dưới dạng "Swift.Array".
George

3
@George Và tương tự cho NSArray; nếu bạn làm lu mờ nó, bạn vẫn có thể gọi nó là Foundation.NSArray.
mờ

1
Vì vậy, không cần phải sắp xếp lịch sử của suy nghĩ về không gian tên trong betas: câu trả lời này hiện đang đứng ở đâu?
Dan Rosenstark

1
@Yar như đã nêu trong các chỉnh sửa. Tên mô-đun là một không gian tên tùy chọn nếu có sự không rõ ràng và hiện có quyền riêng tư để tên mô-đun bị ẩn trừ khi bị lộ và tên có thể bị giới hạn trong một tệp.
matt

2
Điều này đã làm phiền tôi từ lâu, có vẻ như bất kỳ dự án Swift nào cũng không nên sử dụng tiền tố vì những gì Apple đang tuyên bố, tuy nhiên tại thời điểm này vẫn cần một tiền tố, ngay cả với các công cụ sửa đổi truy cập. Mặc dù bạn sẽ không xung đột với các gói hoặc lớp riêng trong khung của Apple, nhưng mọi thứ được khai báo công khai, ví dụ như String, nếu bạn khai báo lại hoặc bất kỳ lớp mới nào, nó sẽ kết thúc bằng cách sử dụng của bạn, trừ khi bạn dĩ nhiên có thói quen đề cập đến tất cả các lớp với không gian tên của nó .... imo không tốt.
Oscar Gomez

19

Trong khi thực hiện một số thử nghiệm với điều này, cuối cùng tôi đã tạo ra các lớp "không gian tên" này trong các tệp riêng của chúng bằng cách mở rộng "gói" gốc. Không chắc chắn nếu điều này chống lại các thực tiễn tốt nhất hoặc nếu nó có bất kỳ hàm ý nào tôi biết về (?)

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)")

GóiOne.swift

import Foundation

struct PackageOne {
}

GóiTwo.swift

import Foundation

struct PackageTwo {
}

GóiOneClass.swift

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

GóiTwoClass.swift

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

Biên tập:

Chỉ cần phát hiện ra rằng việc tạo "gói con" trong đoạn mã trên sẽ không hoạt động nếu sử dụng các tệp riêng biệt. Có lẽ ai đó có thể gợi ý về lý do tại sao đó là trường hợp?

Thêm các tệp sau vào phần trên:

GóiOneSubPackage.swift

import Foundation

extension PackageOne {
    struct SubPackage {
    }
}

GóiOneSubPackageClass.swift

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

Nó gây ra lỗi trình biên dịch: 'SubPackage' không phải là loại thành viên của 'PackageOne'

Nếu tôi di chuyển mã từ GóiOneSubPackageClass.swift sang GóiOneSubPackage.swift thì nó hoạt động. Bất kỳ ai?

Chỉnh sửa 2:

Giải quyết vấn đề này và tìm ra (trong Xcode 6.1 beta 2) rằng bằng cách xác định các gói trong một tệp, chúng có thể được mở rộng trong các tệp riêng biệt:

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

Dưới đây là các tệp của tôi trong một ý chính: https://gist.github.com/mikajauhonen/d4b3e517122ad6a132b8


Thật thú vị, thử nghiệm của bạn như thế nào?
dùng2727195

2
Không chắc ý của bạn là gì khi "thử nghiệm" nhưng tôi đã tiếp tục và bắt đầu xây dựng ứng dụng của mình bằng kỹ thuật trên và nó dường như hoạt động tốt cho đến nay với lời cảnh báo tôi đã thêm vào mục nhập ở trên. Tôi đang làm điều đó chủ yếu là vì tôi thường tổ chức mã của mình theo cách này bằng các ngôn ngữ khác và sẽ rất biết ơn nếu bất kỳ ai có nhiều kiến ​​thức có thể cho tôi biết đó là một ý tưởng tồi cho đến khi tôi đi quá xa! :)
bWlrYWphdWhvbmVu

1
hãy tiếp tục ... đây là những gì chúng ta muốn ... để có thể có cùng một lớp tên trong hai gói khác nhau để có thể tồn tại và được tham chiếu phù hợp (quan trọng hơn là các tệp khác nhau) và nếu nó không hoạt động, toàn bộ ý tưởng về không gian tên là một ý tưởng thất bại ...
user2727195

Bất kỳ tác dụng phụ nào sử dụng "struct" như một cách để hack không gian tên?
Alex Nolasco

Không phải là tôi đã gặp phải liên quan đến hiệu suất như vậy. Xcode (6.1 GM) trong một số trường hợp hiếm hoi phàn nàn về các loại không tồn tại nhưng tôi tin rằng đây có thể là trường hợp khi không cấu trúc mã như thế này. Gần đây tôi đã giải quyết một vấn đề bằng cách thêm tất cả các tệp vào Mục tiêu thử nghiệm của mình, điều này không có ý nghĩa gì nhưng nó đã giải quyết được vấn đề. :)
bWlrYWphdWhvbmVu

12

Tôi tin rằng điều này đạt được bằng cách sử dụng:

struct Foo
{
    class Bar
    {
    }
}

Sau đó, nó có thể được truy cập bằng cách sử dụng:

var dds = Foo.Bar();

1
Tôi vẫn không hài lòng với cách thực hiện các không gian tên ... nếu tôi có mười lớp khác nhau trong một không gian tên, và trên hết tôi thích giữ các lớp trong các tệp riêng lẻ của chúng, không muốn làm mờ một lớp tập tin / struct với tất cả các lớp, bất kỳ đề xuất Kevin.
dùng2727195

2
Tôi tự hỏi tại sao họ không nghĩ bao gồm các gói, đó là những gì chúng ta cần, không phải là không gian tên, ý tôi là nhìn vào các ngôn ngữ cấp cao khác như Java, C #, ActionScript, tất cả chúng đều có các gói, không gian tên trong ngữ cảnh này không khác gì sử dụng NS hoặc các tiền tố khác cho các lớp dự án của bạn
user2727195

1
Không thể giúp tự hỏi nếu sử dụng structs như một cách để hack không gian tên có thể gây ra vấn đề không xác định.
Alex Nolasco

1
Đây là cách giải quyết tốt đẹp cho nó. Tôi đã thử sử dụng phương pháp này nhưng phải dừng lại ngay lập tức. Khi tôi cố gắng không gian tên các lớp liên quan đến chế độ xem của mình (giả sử là CustomTableViewCell), trình tự động hoàn thành trong trình xây dựng giao diện đã không đề xuất điều đó. Tôi sẽ phải sao chép và dán tên lớp theo cách thủ công nếu tôi đã sử dụng phương pháp này.
ArG

1
Thông thường bạn sẽ sử dụng một enum, không phải a struct, vì vậy bạn không thể khởi tạo a Foo.
Kevin

7

Swift sử dụng các mô-đun giống như trong python (xem tại đâyđây ) và như @Kevin Sylvestre đề xuất, bạn cũng có thể sử dụng các kiểu lồng nhau làm không gian tên.

Và để mở rộng câu trả lời từ @Daniel A. White, trong WWDC, họ đã nói về các mô-đun nhanh chóng.

Cũng ở đây được giải thích:

Các kiểu suy luận làm cho mã sạch hơn và ít bị lỗi hơn, trong khi các mô-đun loại bỏ các tiêu đề và cung cấp các không gian tên.


2
Tôi đang tìm kiếm các gói như cấu trúc như được đề cập trong liên kết thứ hai của bạn 6.4 Gói (Python), các không gian tên như các kiểu lồng nhau không thể đi xa được, nếu tôi có 10 lớp khác nhau và trong các tệp khác nhau trong một không gian tên hoặc giả sử gói ???
dùng2727195

7
  • Không gian tên rất hữu ích khi bạn cần xác định lớp có cùng tên với lớp trong khung hiện có.

  • Giả sử ứng dụng của bạn có MyApptên và bạn cần khai báo tùy chỉnh của mình UICollectionViewController.

Bạn không cần phải thêm tiền tố và lớp con như thế này:

class MAUICollectionViewController: UICollectionViewController {}

Làm như thế này:

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

Tại sao? . Bởi vì những gì bạn đã khai báo được khai báo trong mô-đun hiện tại , đó là mục tiêu hiện tại của bạn . Và UICollectionViewControllertừ UIKitđược tuyên bố trongUIKit mô-đun.

Làm thế nào để sử dụng nó trong mô-đun hiện tại?

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

Làm thế nào để phân biệt chúng với một mô-đun khác?

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

3

Bạn có thể sử dụng extensionđể sử dụng structcách tiếp cận được đề cập cho không gian tên mà không cần phải thụt lề tất cả các mã của bạn về phía bên phải. Tôi đã từng đùa giỡn với điều này một chút và tôi không chắc là tôi có thể tạo ra ControllersViews không gian tên như trong ví dụ dưới đây, nhưng nó minh họa cho việc nó có thể đi được bao xa:

Hồ sơ.swift :

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

Hồ sơ / 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
  }
}

Hồ sơ / Lượt xem / Edit.swift

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

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

Tôi chưa sử dụng điều này trong một ứng dụng vì tôi chưa cần mức độ tách biệt này nhưng tôi nghĩ đó là một ý tưởng thú vị. Điều này loại bỏ sự cần thiết của các hậu tố lớp chẵn như hậu tố phổ biến * ViewControll dài khó chịu.

Tuy nhiên, nó không rút ngắn bất cứ điều gì khi được tham chiếu, chẳng hạn như trong các tham số phương thức như thế này:

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

2

Trong trường hợp bất kỳ ai cũng tò mò, kể từ ngày 10 tháng 6 năm 2014, đây là một lỗi đã biết trong Swift:

Từ SevenTenEleven

"Lỗi đã biết, xin lỗi! Rdar: // vấn đề / 17127940 Các loại Swift đủ điều kiện theo tên mô-đun của chúng không hoạt động."


Bài đăng của per @ matt bên dưới, đây là một lỗi đã biết trong Swift ngay bây giờ.
Adam Venturella

Điều này đã được sửa trong Beta 3 (Phát hành ngày 7 tháng 7 năm 2014)
Adam Venturella
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.