Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Namespaces in Swift?

Tags:

macos

ios

swift

People also ask

Is there namespace in Swift?

Even though Swift doesn't support namespaces within modules, there are a few viable solutions to this problem. The first solution uses structs to create namespaces and it looks something like this. We define a struct, API , and declare one or more static constant properties.

What is namespace iOS?

A dynamic property type that allows access to a namespace defined by the persistent identity of the object containing the property (e.g. a view). iOS 14.0+ iPadOS 14.0+ macOS 11.0+ Mac Catalyst 14.0+ tvOS 14.0+ watchOS 7.0+

What is a module Swift?

A module is a single unit of code distribution—a framework or application that's built and shipped as a single unit and that can be imported by another module with Swift's import keyword. Each build target (such as an app bundle or framework) in Xcode is treated as a separate module in Swift.


I would describe Swift's namespacing as aspirational; it's been given a lot of advertising that doesn't correspond to any meaningful reality on the ground.

For example, the WWDC videos state that if a framework you're importing has a class MyClass and your code has a class MyClass, those names do not conflict because "name mangling" gives them different internal names. In reality, however, they do conflict, in the sense that your own code's MyClass wins, and you can't specify "No no, I mean the MyClass in the framework" — saying TheFramework.MyClass doesn't work (the compiler knows what you mean, but it says it can't find such a class in the framework).

My experience is that Swift therefore is not namespaced in the slightest. In turning one of my apps from Objective-C to Swift, I created an embedded framework because it was so easy and cool to do. Importing the framework, however, imports all the Swift stuff in the framework - so presto, once again there is just one namespace and it's global. And there are no Swift headers so you can't hide any names.

EDIT: In seed 3, this feature is now starting to come online, in the following sense: if your main code contains MyClass and your framework MyFramework contains MyClass, the former overshadows the latter by default, but you can reach the one in the framework by using the syntax MyFramework.MyClass. Thus we do in fact have the rudiments of a distinct namespace!

EDIT 2: In seed 4, we now have access controls! Plus, in one of my apps I have an embedded framework and sure enough, everything was hidden by default and I had to expose all the bits of the public API explicitly. This is a big improvement.


Answered by SevenTenEleven in the Apple dev forum:

Namespaces are not per-file; they're per-target (based on the "Product Module Name" build setting). So you'd end up with something like this:

import FrameworkA
import FrameworkB

FrameworkA.foo()

All Swift declarations are considered to be part of some module, so even when you say "NSLog" (yes, it still exists) you're getting what Swift thinks of as "Foundation.NSLog".

Also Chris Lattner tweeted about namespacing.

Namespacing is implicit in Swift, all classes (etc) are implicitly scoped by the module (Xcode target) they are in. no class prefixes needed

Seems to be very different what I have been thinking.


While doing some experimentation with this I ended up creating these "namespaced" classes in their own files by extending the root "package". Not sure if this is against best practices or if it has any implications I'm mot aware of(?)

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

Edit:

Just found out that creating "subpackages" in above code wont work if using separate files. Maybe someone can hint on why that would be the case?

Adding following files to the above:

PackageOneSubPackage.swift

import Foundation

extension PackageOne {
    struct SubPackage {
    }
}

PackageOneSubPackageClass.swift

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

Its throwing a compiler error: 'SubPackage' is not a member type of 'PackageOne'

If I move the code from PackageOneSubPackageClass.swift to PackageOneSubPackage.swift it works. Anyone?

Edit 2:

Fiddling around with this still and found out (in Xcode 6.1 beta 2) that by defining the packages in one file they can be extended in separate files:

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

Here are my files in a gist: https://gist.github.com/mikajauhonen/d4b3e517122ad6a132b8


I believe this is achieved using:

struct Foo
{
    class Bar
    {
    }
}

Then it can be accessed using:

var dds = Foo.Bar();

  • Namespaces are useful when you need to define class with the same name as class in existing framework.

  • Suppose your app has MyApp name, and you need to declare your custom UICollectionViewController.

You don't need to prefix and subclass like this:

class MAUICollectionViewController: UICollectionViewController {}

Do it like this:

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

Why?. Because what you've declared is declared in current module, which is your current target. And UICollectionViewController from UIKit is declared in UIKit module.

How to use it within current module?

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

How to distinguish them from another module?

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

Swift uses modules much like in python (see here and here) and as @Kevin Sylvestre suggested you can also use the nested types as namespaces.

And to extend the answer from @Daniel A. White, in WWDC they were talking about the modules in swift.

Also here is explained:

Inferred types make code cleaner and less prone to mistakes, while modules eliminate headers and provide namespaces.


You can use extension to use the mentioned structs approach for namespacing without having to indent all of your code towards the right. I've been toying with this a bit and I'm not sure I'd go as far as creating Controllers and Views namespaces like in the example below, but it does illustrate how far it can go:

Profiles.swift:

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

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

Profiles/Views/Edit.swift

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

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

I haven't used this in an app since I haven't needed this level of separation yet but I think it's an interesting idea. This removes the need for even class suffixes such as the ubiquitous *ViewController suffix which is annoyingly long.

However, it doesn't shorten anything when it's referenced such as in method parameters like this:

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