7

What ways do you know to prevent an object construction using Swift programming language?

In C++ I can simply make the constructor private like this:

struct A {
 private:
  A() {};
};

int main()
{
  // Doesn't compile because the constructor is private.
  A obj;
  return 0;
}

When I do a similar thing in Swift (I tried it in playground) the code compiles just fine:

class A {
  private init() {}
}

let obj = A()

UPDATE:

Ok, this question is marked as a duplicate. But I think this is a misunderstanding. What I'm asking about is what are the best practices you know to prevent object construction in Swift. All I want to achieve is to make it clear to the users of my class that it should not be constructible.

UPDATE 2:

As this question is still here, I think, it needs some more clarifications for those who still can't comprehend what I really want.

Given a class that is used as a wrapper for some useful constants such as the following:

class Constants {
 static let someConstant1 = "CONSTANT_VALUE1"
 static let someConstant2 = "CONSTANT_VALUE2"
 //....etc...
}

what option can be considered as a best practice:

  • Leave it as is and don't worry about the possibility of objects creation outside this class;
  • Add private init() {} to prevent creation of the objects outside the current file;
  • Use init? and return nil to indicate that the objects must not be created as was suggested in the comments.

Hope the question is more clear now.

Stan Mots
  • 1,193
  • 2
  • 15
  • 16
  • No, it's not. I'm not asking about the access modifiers. I need to know about _the ways_ to prevent an object construction. I used the example above just to give you an idea of what I want. – Stan Mots Apr 14 '16 at 11:00
  • How do you plan to construct an object without being able to construct it? – BallpointBen Apr 14 '16 at 11:29
  • *Ok, this question is marked as a duplicate of this. But, in my opinion, they are different.*--You have to realize the purpose of SO. It is not to be used to discuss programming problems, rather it is to be used as a tool to apply strict rules as broadly as possible to silence people. – 7stud Apr 14 '16 at 11:47
  • `private init` *is* the solution and it works – just not from within the same source file. – Martin R Apr 14 '16 at 11:48
  • @MartinR Do you mean that this is the only one possible solution? But 7stud gave nice example about using _init?_ as an indicator that the object must not be created. – Stan Mots Apr 14 '16 at 11:54
  • @7stud, I don't understand, what the problem. I just asked simple question. I was not going to discuss programming problems. – Stan Mots Apr 14 '16 at 11:56
  • @Storix: Perhaps you can tell what you *actually* want. My impression was that you want a class that can only be instantiated via factory methods, in that case an failable initializer which always returns nil won't help. – If you want the class only as wrapper for constants then you can define an `enum` without cases instead. That gives you the namespace, but no enum value can be instantiated. – I don't see a use case for a class which cannot be instantiated *at all.* – Martin R Apr 14 '16 at 12:19
  • @Storix: Also – unless I am mistaken – in C++ the `private` modifier restricts visibility to the class itself, it does not prevent the object from being constructed at all. An exact analogue in Swift does not exist. So your example might be misleading (depending on what you really want). – Martin R Apr 14 '16 at 12:32
  • @MartinR, In C++ private constructor prevents objects creation outside the class itself. This is exactly what I wanted to achieve. Sorry, I didn't know that Swift doesn't have an equivalent mechanism. You can freely delete this question if you think it's inappropriate for SO. – Stan Mots Apr 14 '16 at 13:24
  • @Storix it works exactly the same way now in Swift 4 – pronebird Dec 11 '17 at 10:43

2 Answers2

9

From Apple's guide to Swift:

Private access restricts the use of an entity to its own defining source file. Use private access to hide the implementation details of a specific piece of functionality.

Your playground file is all one file, so privacy is not enforced.

For instance, if you create a new project and add a file called Dog.swift to the project that looks like this:

import Foundation

class Dog {
    private init() {
        print("hello")
    }
}

class Cat {
    var d = Dog()
}

in ViewController.swift, you can write:

override func viewDidLoad() {

    let c = Cat()  //=>hello

}

But, if you try:

override func viewDidLoad() {

    let d = Dog() 

}

Xcode will flag that as an error before you even compile the program:

'Dog' cannot be constructed because it has no accessible initializers

Response to comment:

class A {
    init?() {
        return nil
    }

    func greet() {
        print("hello")
    }
}

let x = A()

if let x = x {
    x.greet()
}
else {
    print("nice try")  //=> nice try
}
7stud
  • 46,922
  • 14
  • 101
  • 127
  • Thanks, but that is not the answer to my question. I still need to know how can I restrict construction of the objects in Swift. It would be great if you could provide me some best practices examples. – Stan Mots Apr 14 '16 at 11:05
  • @Storix, I added an example. – 7stud Apr 14 '16 at 11:08
  • 1
    so, there is no way to prevent object construction within the same file? Am I right? – Stan Mots Apr 14 '16 at 11:15
  • What would be the use of `class A`? *Nobody* can create an object, not even a factory (class/type) method in `A`. – Martin R Apr 14 '16 at 11:31
  • @MartinR, Storix is being very literal. I have now answered the question literally. – 7stud Apr 14 '16 at 11:40
  • @MartinR, how about using a class as a wrapper for the constants? Why should anybody wish to create objects of such a class? – Stan Mots Apr 14 '16 at 11:48
  • @StanMots If you want to create a wrapper type for static values, consider using an enum: https://stackoverflow.com/questions/39022242/difference-between-static-enum-and-static-struct – John Montgomery Mar 20 '18 at 23:34
0

i tried this, hope this is what you want

 private class My {
  static var singletonObj = My()
 } 

let obj = My() // error
let obj1 = My.singletonObj
Sahil
  • 9,096
  • 3
  • 25
  • 29
  • In playground your code gives such error _"error: constant must be declared private"_. To compile it successfully we must add private modifier to the _obj1_. But, anyway, thanks! This is nice solution. – Stan Mots Apr 14 '16 at 11:24
  • 2
    *Both* lines compile if you add a `private` modifier. I don't see how this helps. – Martin R Apr 14 '16 at 11:28
  • Heh, thanks, @MartinR, I missed this case. Yeah, this is not a solution I wanted. – Stan Mots Apr 14 '16 at 11:31
  • I also ignore the warning message. And 7 stud is right. – Sahil Apr 14 '16 at 18:04
  • I don't think so that will work because if we can not access a object of My calss then how we can access its property. its out of scope when we are implementing this. – Pradeep Singh Apr 23 '21 at 06:54