Swift: Unwrap optional to the instance variable properly - swift

I'm looking for the right way of unwrapping optional to an instance variable in swift.
I have a singleton class, shared property of which can be nil, and I'm trying to assign the instance of the singleton in the failable initializer of another class so that I can use the singleton instance without caring of unwrapping it every time.
It looks like this:
class A {
static let shared = A()
let b = 1
private init?() {
return nil
}
}
class B {
let a: A
init?() {
if A.shared != nil {
a = A.shared!
} else {
return nil
}
print(a.b)
}
}
B()
Is there any way of doing this in a shorter way (using guard, if, etc.)?

You can write the init? of B as follows:
init?() {
guard let a = A.shared else { return nil }
self.a = a
print(a.b)
}
It's best to avoid code in the pattern:
if someVar != nil {
x = someVar!
}
guard let or if let exist to avoid such constructs.
But there is no way to avoid dealing with your optional singleton other than not making it optional. It's unusual to have an optional singleton instance.

Related

Safely unwrapping optional with guard let in init()

I think I probably missed the point of how this works but I have a class that needs to use a global optional value in several of its methods and right now I unwrapped it inside every method but I thought I could just unwrap the value in init(). Am I doing it wrong or is this now how it's supposed to work? - Thank you.
let iCloudPath = FileManager.default.url(forUbiquityContainerIdentifier: nil)?.appendingPathComponent("Documents")
class iCloudManager {
init() {
guard let iCloudPath = iCloudPath else { return }
}
function1(){
// uses iCloudPath but returns 'Value of optional type 'URL?' must be unwrapped to a value of type 'URL''
}
function2(){
// uses iCloudPath but returns 'Value of optional type 'URL?' must be unwrapped to a value of type 'URL''
}
}
Store the result as a property of your objects. Better yet, use a static property, not a global.
class iCloudManager {
static let defaultPath = FileManager.default.url(forUbiquityContainerIdentifier: nil)?.appendingPathComponent("Documents")
let path: URL
init?() {
guard let path = iCloudManager.defaultPath else { return nil }
self.path = path
}
func function1() {
// uses self.path
}
func function2() {
// uses self.path
}
}

super init with data error

I have a convenience initializer that calls onto an initializer that calls onto a super class initializer with header init!(data: Data!). What I don't understand is why I am getting the following error:
fatal error: unexpectedly found nil while unwrapping an Optional value.
I have tried initializing a random Data object with no data but I still obtain this error any ideas?
Code:
Convenience init(itemId: String) {
let d: Data = Data.init()
self.init(data: d) // error here!
}
required init!(data: Data?) {
super.init(data: data)
}
super class from obj c library:
-(id)initWithData:(NSData*)data {
if ([self init]) {
//some code
}
return nil
}
You're using implicitly unwrapped optional parameters and initializers. If you'd like to have a failable initializer, you should use init? instead. As for passing in an argument that is implicitly unwrapped. That is really dangerous, too. Marking things as implicitly unwrapped is very convenient for avoiding the Swift compiler complaining, but it will often lead to this problem.
The problem is your call to super.init is returning nil.
This example shows you a safe way to do failable initialization.
// This is a stand in for what your super class is doing
// Though I can't tell you why it is returning nil
class ClassB {
required init?(data: Data?) {
return nil
}
}
class ClassA: ClassB {
convenience init?(itemId: String) {
let d: Data = Data.init()
self.init(data: d) // error here!
}
required init?(data: Data?) {
super.init(data: data)
}
}
if let myObject = ClassA.init(itemId: "ABC") {
// non-nil
} else {
// failable initializer failed
}

Save struct in background mutating function

I'm trying to save a struct in background but I get this error :
closure cannot implicitly capture a mutating self parameter
This is my code :
//MARK: Parse self methods
fileprivate mutating func ParseSave(_ completionBlock: #escaping SuccessCompletionBlock) {
let message: PFObject = PFObject(className: "Message")
if let id = self.id {
//this object exit just update it
message.objectId = id
}
// set attributes
if let text = self.text {
message["text"] = text
}
message["sender"] = PFUser(withoutDataWithObjectId: self.sender.id)
message["conversation"] = PFObject(withoutDataWithClassName: "Conversation", objectId: conversationId)
message["viewed"] = self.viewed
message.saveInBackground { (success, error) in
if success {
// the next 3 lines cause the error : (when I try to update the struct - self )
self.id = message.objectId
self.createdAt = message.createdAt ?? self.createdAt
self.updatedAt = message.updatedAt ?? self.updatedAt
}
completionBlock(success, error)
}
}
I've checked those question: 1 - 2 I've added the #escaping
but didn't work.
I think it will help if we minimally elicit the error message you're getting. (For delay, see dispatch_after - GCD in swift?.)
struct S {
var name = ""
mutating func test() {
delay(1) {
self.name = "Matt" // Error: Closure cannot ...
// ... implicitly capture a mutating self parameter
}
}
}
The reason lies in the peculiar nature of struct (and enum) mutation: namely, it doesn't really exist. When you set a property of a struct, what you're really doing is copying the struct instance and replacing it with another. That is why only a var-referenced struct instance can be mutated: the reference must be replaceable in order for the instance to be mutable.
Now we can see what's wrong with our code. Obviously it is legal for a mutating method to mutate self; that is what mutating means. But in this case we are offering to go away for a while and then suddenly reappear on the scene (after 1 second, in this case) and now mutate self. So we are going to maintain a copy of self until some disconnected moment in the future, when self will suddenly be somehow replaced. That is incoherent, not least because who knows how the original self may have been mutated in the meantime, rendering our copy imperfect; and the compiler prevents it.
The same issue does not arise with a nonescaping closure:
func f(_ f:()->()) {}
struct S {
var name = ""
mutating func test() {
f {
self.name = "Matt" // fine
}
}
}
That's because the closure is nonescaping; it is executed now, so the incoherency about what will happen in the future is absent. This is an important difference between escaping and nonescaping closures, and is one of the reasons why they are differentiated.
Also, the same issue does not arise with a class:
class C {
var name = ""
func test() {
delay(1) {
self.name = "Matt" // fine
}
}
}
That's because the class instance is captured by reference in the closure, and a class instance is mutable in place.
(See also my little essay here: https://stackoverflow.com/a/27366050/341994.)

Swift initialization stored property outside init method of class issue

I have an swift class
class ApplicationManager {
var fanMode: FanMode
init()
{
self.applyDefaultSettings()
}
func applyDefaultSettings()
{
if let unwrappedFanMode = userDefaults.valueForKey(Consts.kStoredFanMode) as? FanMode {
self.fanMode = unwrappedFanMode
}
}
}
The code above throws this issue:
Use of 'self' in method call 'applyDefaultSettings' before all stored properties are initialized
What should I do here? So as message say I need to initialize all stored properties before I call any other method of class. So it means in init method I should initialize at least fanMode property. But I want to have method that apply kind of default settings for my properties to provide simple readability and clean code architecture. But maybe it's ok to use initializer of class to init all needed fields.
You also can do it by using this code:
var fanMode: FanMode = {
if let unwrappedFanMode = userDefaults.valueForKey(Consts.kStoredFanMode) as? FanMode {
return unwrappedFanMode
} else {
return FanMode()//some default implementation
}
}()
It is readable as You want.
As per Apple documentation, Swift does not allow you to left uninitialised variables or constants. If you want to set some default settings then assign your variables with initial values that will act as your default settings and later you can change them.
All instance properties must be initialized in the init method. You can either move the initialization to the init (defaultMode would be your default value if userDefaults is nil):
init() {
fanMode = (userDefaults?.valueForKey(Consts.kStoredFanMode) as? FanMode) ?? defaultMode
}
Set a default value for that property, for example:
var fanMode: FanMode = defaultMode
Or you can make your fanMode nullable:
var fanMode: FanMode? = nil
You can use an implicity unwrapped optional. Just add a ! to the variable declaration.
class ApplicationManager {
var fanMode: FanMode! //Implicitly unwrapped optional.
init()
{
self.applyDefaultSettings()
}
func applyDefaultSettings()
{
if let unwrappedFanMode = userDefaults.valueForKey(Consts.kStoredFanMode) as? FanMode {
self.fanMode = unwrappedFanMode
}
}
}
Basically it tricks xCode into telling it "Hey this variable is initialized and value will never be nil". But you want to be careful using these as if it does turn out to be nil your program will crash. But in your case it should be fine since you initialize it in the init method so it will never be nil before using it.

Checking if a Swift class conforms to a protocol and implements an optional function?

I'm writing a helper function in Swift for use in SpriteKit games that will check if the collision detention has been set up correctly.
I want to check that my GameScene implements the protocol SKPhysicsContactDeletegate and also contains the didBeginContact function.
I have the following code, written with the help of Xcode's auto-complete:
if GameScene(conformsToProtocol(SKPhysicsContactDelegate)) {
if GameScene(respondsToSelector(didBeginContact(SKPhysicsContact))) {
print("Self implements SKPhysicsContactDelegate and didBeginContact appears to be present")
}
}
Xcode then complains about my conformsToProtocol, complaining that
'Argument labels '(_:)' do not match any available overloads'
with no suggestion how to fix. It also objects to respondsToSelector, stating that
'Cannot convert value of type '(SKPhysicsContact).Type' (aka
'SKPhysicsContact.Type') to expected argument type 'SKPhysicsContact'
How can I check if my GameScene conforms to this protocol and also implements this function?
Edit: Here's my code based upon the answers:
if GameScene.self is SKPhysicsContactDelegate {
print("Yes it's a delegate")
}
Output: Yes it's a delegate
let yy = (GameScene.self as? SKPhysicsContactDelegate)?.didBeginContact
print("yy is \(yy)")
Output: yy is nil
if (GameScene.self as? SKPhysicsContactDelegate)?.didBeginContact != nil {
print("Yes it's a delegate and the function is there")
}
No output.
You are still thinking in Objective-C, embrace Swift!
Assuming that your protocol looks like this:
#objc protocol SKPhysicsContactDelegate {
optional func didBeginContact()
}
Try this:
if let delegate = gameScene as? SKPhysicsContactDelegate {
delegate.didBeginContact?()
}
Or a one liner:
(gameScene as? SKPhysicsContactDelegate)?.didBeginContact?()
Notice the ? after the method name in the call? It's because that method is optional and it won't get called if the object doesn't implement that method. And the if let branch won't get executed if the object doesn't conforms to SKPhysicsContactDeletegate protocol.
Check method existence without call
To check the existence of the method itself before calling, just omit the method call to get a reference to that methodand check it like any other variable:
if let method = (gameScene as? SKPhysicsContactDelegate)?.didBeginContact {
print("gameScene conforms to SKPhysicsContactDelegate and implements didBeginContact")
// Call it later whenever you want
method()
}
If you don't need to call it later, just check for nil:
if (gameScene as? SKPhysicsContactDelegate)?.didBeginContact != nil {
print("gameScene conforms to SKPhysicsContactDelegate and implements didBeginContact")
}
Check for static methods
Checking for optional static methods uses the same approach, but requires the class object instead of an instance of the class:
if (GameScene.self as? OptionalProtocol.Type)?.staticMethod != nil {
print("gameScene conforms to OptionalProtocol and implements staticMethod")
}
Notice GameScene.self for obtaining the object type and <protocol>.Type to cast to the protocol class instead of a protocol instance.
Full sample
Attached full sample for Playgrounds, Swift script or any online Swift compiler:
import Foundation
#objc protocol OptionalProtocol {
optional func instanceMethod()
optional static func staticMethod()
}
class Nothing {}
class Something: OptionalProtocol {}
class Bar: NSObject, OptionalProtocol {
func instanceMethod() {
print("Instance method")
}
}
class Foo: NSObject, OptionalProtocol {
static func staticMethod() {
print("Static method")
}
}
// Cast instances to 'Any' and classes to 'AnyClass'
let nothing: Any = Nothing()
let nothingClass: AnyClass = Nothing.self
let something: Any = Something()
let somethingClass: AnyClass = Something.self
let bar: Any = Bar()
let barClass: AnyClass = Bar.self
let foo: Any = Foo()
let fooClass: AnyClass = Foo.self
nothing is OptionalProtocol // false
(nothing as? OptionalProtocol)?.instanceMethod != nil // false
(nothing as? OptionalProtocol)?.instanceMethod?() // Does nothing
(nothingClass as? OptionalProtocol.Type)?.staticMethod != nil // false
(nothingClass as? OptionalProtocol.Type)?.staticMethod?() != nil // Does nothing
something is OptionalProtocol // true
(something as? OptionalProtocol)?.instanceMethod != nil // false
(something as? OptionalProtocol)?.instanceMethod?() // Does nothing
(somethingClass as? OptionalProtocol.Type)?.staticMethod != nil // false
(somethingClass as? OptionalProtocol.Type)?.staticMethod?() != nil // Does nothing
bar is OptionalProtocol // true
(bar as? OptionalProtocol)?.instanceMethod != nil // true
(bar as? OptionalProtocol)?.instanceMethod?() // Prints 'Instance method'
(barClass as? OptionalProtocol.Type)?.staticMethod != nil // false
(barClass as? OptionalProtocol.Type)?.staticMethod?() != nil // Does nothing
foo is OptionalProtocol // true
(foo as? OptionalProtocol)?.instanceMethod != nil // false
(foo as? OptionalProtocol)?.instanceMethod?() // Does nothing
(fooClass as? OptionalProtocol.Type)?.staticMethod != nil // true
(fooClass as? OptionalProtocol.Type)?.staticMethod?() != nil // Prints 'Static method'
respondsToSelector fails, because it expects an instance of SKPhysicsContact and not SKPhysicsContact.type.
To check if an object implements an interface, you can use is.
So for example:
protocol Test {
func foo();
}
class TestImpl : Test {
func foo() {
print("bar")
}
}
let a = TestImpl()
let b = String()
print(a is Test) // true
print(b is Test) // false