ObjectIdentifier needed for Swift equality? - ios

We have multiple instances of a custom Swift class, which inherits from SKSpriteNode, and were able to execute the following code (grossly simplified for this question) correctly:
let instance1 = CustomClass()
let instance2 = CustomClass()
let instance3 = CustomClass()
let instance4 = CustomClass()
let array1 = [instance1, instance2]
let array2 = [instance3, instance4]
func check(testInstance: CustomClass) -> Bool {
return array1.filter({ $0 == testInstance }).count > 0
}
check(testInstance: instance3)
In other words, executing check(testInstance: instance3) returned false as expected.
However, we made a bunch of changes, and check stopped working.
CustomClass does not implement the Equatable protocol. We just want to detect unique instances.
It only started working when we used ObjectIdentifier, meaning the function changed to this:
func check(testInstance: CustomClass) -> Bool {
return array1.filter({ ObjectIdentifier($0) == ObjectIdentifier(testInstance) }).count > 0
}
Why is ObjectIdentifier needed, and when should it be used for object equality?
This was written with Swift 3.

Why is ObjectIdentifier needed, and when should it be used for object equality?
You don't need to use ObjectIdentifier in order to perform an identity comparison in this case, you can simply use the identity operator === instead which, as Martin says here, for class instances is equivalent to using ObjectIdentifier's == overload:
func check(testInstance: CustomClass) -> Bool {
return array1.contains(where: { $0 === testInstance })
}
Also note we're using contains(where:) over filter{...}.count > 0, as the former will short-circuit upon finding a matching element, whereas the latter evaluates the entire sequence (and creates an unnecessary intermediate array).
The direct use of == to perform an identity comparison of objects may have worked due to the fact that CustomClass ultimately inherits from NSObject, which conforms to Equatable by defining an == overload that calls isEqual(_:), which by default performs an identity comparison.
However in general, this should not be relied upon – the implementation of isEqual(_:) can be overridden to perform a comparison based on property values rather than identity. Furthermore, semantically Equatable requires that the implementation of == is based all on visible aspects (i.e property values) of the instances being compared.
From the documentation:
Equality implies substitutability — any two instances that compare
equally can be used interchangeably in any code that depends on their
values. To maintain substitutability, the == operator should take into
account all visible aspects of an Equatable type.
Therefore using == for an identity comparison on your class was never correct, even though it may have worked initially.
As for when ObjectIdentifier should be used, really you should never need it just to perform an identity comparison. For classes, you should use the === operator, and for metatypes, you should simply use the == overload defined specifically for them (as in that case, identity just happens to equality, as each new metatype instance is unique).
The main use of ObjectIdentifier is really its hashValue implementation, which is derived from the pointer value of the thing that it's initialised with. This can be useful, for example, in allowing metatypes to be Dictionary keys (compare Make a Swift dictionary where the key is "Type"?).

Related

Associatedtype depends on protocol [duplicate]

Why doesn't this Swift code compile?
protocol P { }
struct S: P { }
let arr:[P] = [ S() ]
extension Array where Element : P {
func test<T>() -> [T] {
return []
}
}
let result : [S] = arr.test()
The compiler says: "Type P does not conform to protocol P" (or, in later versions of Swift, "Using 'P' as a concrete type conforming to protocol 'P' is not supported.").
Why not? This feels like a hole in the language, somehow. I realize that the problem stems from declaring the array arr as an array of a protocol type, but is that an unreasonable thing to do? I thought protocols were there exactly to help supply structs with something like a type hierarchy?
Why don't protocols conform to themselves?
Allowing protocols to conform to themselves in the general case is unsound. The problem lies with static protocol requirements.
These include:
static methods and properties
Initialisers
Associated types (although these currently prevent the use of a protocol as an actual type)
We can access these requirements on a generic placeholder T where T : P – however we cannot access them on the protocol type itself, as there's no concrete conforming type to forward onto. Therefore we cannot allow T to be P.
Consider what would happen in the following example if we allowed the Array extension to be applicable to [P]:
protocol P {
init()
}
struct S : P {}
struct S1 : P {}
extension Array where Element : P {
mutating func appendNew() {
// If Element is P, we cannot possibly construct a new instance of it, as you cannot
// construct an instance of a protocol.
append(Element())
}
}
var arr: [P] = [S(), S1()]
// error: Using 'P' as a concrete type conforming to protocol 'P' is not supported
arr.appendNew()
We cannot possibly call appendNew() on a [P], because P (the Element) is not a concrete type and therefore cannot be instantiated. It must be called on an array with concrete-typed elements, where that type conforms to P.
It's a similar story with static method and property requirements:
protocol P {
static func foo()
static var bar: Int { get }
}
struct SomeGeneric<T : P> {
func baz() {
// If T is P, what's the value of bar? There isn't one – because there's no
// implementation of bar's getter defined on P itself.
print(T.bar)
T.foo() // If T is P, what method are we calling here?
}
}
// error: Using 'P' as a concrete type conforming to protocol 'P' is not supported
SomeGeneric<P>().baz()
We cannot talk in terms of SomeGeneric<P>. We need concrete implementations of the static protocol requirements (notice how there are no implementations of foo() or bar defined in the above example). Although we can define implementations of these requirements in a P extension, these are defined only for the concrete types that conform to P – you still cannot call them on P itself.
Because of this, Swift just completely disallows us from using a protocol as a type that conforms to itself – because when that protocol has static requirements, it doesn't.
Instance protocol requirements aren't problematic, as you must call them on an actual instance that conforms to the protocol (and therefore must have implemented the requirements). So when calling a requirement on an instance typed as P, we can just forward that call onto the underlying concrete type's implementation of that requirement.
However making special exceptions for the rule in this case could lead to surprising inconsistencies in how protocols are treated by generic code. Although that being said, the situation isn't too dissimilar to associatedtype requirements – which (currently) prevent you from using a protocol as a type. Having a restriction that prevents you from using a protocol as a type that conforms to itself when it has static requirements could be an option for a future version of the language
Edit: And as explored below, this does look like what the Swift team are aiming for.
#objc protocols
And in fact, actually that's exactly how the language treats #objc protocols. When they don't have static requirements, they conform to themselves.
The following compiles just fine:
import Foundation
#objc protocol P {
func foo()
}
class C : P {
func foo() {
print("C's foo called!")
}
}
func baz<T : P>(_ t: T) {
t.foo()
}
let c: P = C()
baz(c)
baz requires that T conforms to P; but we can substitute in P for T because P doesn't have static requirements. If we add a static requirement to P, the example no longer compiles:
import Foundation
#objc protocol P {
static func bar()
func foo()
}
class C : P {
static func bar() {
print("C's bar called")
}
func foo() {
print("C's foo called!")
}
}
func baz<T : P>(_ t: T) {
t.foo()
}
let c: P = C()
baz(c) // error: Cannot invoke 'baz' with an argument list of type '(P)'
So one workaround to to this problem is to make your protocol #objc. Granted, this isn't an ideal workaround in many cases, as it forces your conforming types to be classes, as well as requiring the Obj-C runtime, therefore not making it viable on non-Apple platforms such as Linux.
But I suspect that this limitation is (one of) the primary reasons why the language already implements 'protocol without static requirements conforms to itself' for #objc protocols. Generic code written around them can be significantly simplified by the compiler.
Why? Because #objc protocol-typed values are effectively just class references whose requirements are dispatched using objc_msgSend. On the flip side, non-#objc protocol-typed values are more complicated, as they carry around both value and witness tables in order to both manage the memory of their (potentially indirectly stored) wrapped value and to determine what implementations to call for the different requirements, respectively.
Because of this simplified representation for #objc protocols, a value of such a protocol type P can share the same memory representation as a 'generic value' of type some generic placeholder T : P, presumably making it easy for the Swift team to allow the self-conformance. The same isn't true for non-#objc protocols however as such generic values don't currently carry value or protocol witness tables.
However this feature is intentional and is hopefully to be rolled out to non-#objc protocols, as confirmed by Swift team member Slava Pestov in the comments of SR-55 in response to your query about it (prompted by this question):
Matt Neuburg added a comment - 7 Sep 2017 1:33 PM
This does compile:
#objc protocol P {}
class C: P {}
func process<T: P>(item: T) -> T { return item }
func f(image: P) { let processed: P = process(item:image) }
Adding #objc makes it compile; removing it makes it not compile again.
Some of us over on Stack Overflow find this surprising and would like
to know whether that's deliberate or a buggy edge-case.
Slava Pestov added a comment - 7 Sep 2017 1:53 PM
It's deliberate – lifting this restriction is what this bug is about.
Like I said it's tricky and we don't have any concrete plans yet.
So hopefully it's something that language will one day support for non-#objc protocols as well.
But what current solutions are there for non-#objc protocols?
Implementing extensions with protocol constraints
In Swift 3.1, if you want an extension with a constraint that a given generic placeholder or associated type must be a given protocol type (not just a concrete type that conforms to that protocol) – you can simply define this with an == constraint.
For example, we could write your array extension as:
extension Array where Element == P {
func test<T>() -> [T] {
return []
}
}
let arr: [P] = [S()]
let result: [S] = arr.test()
Of course, this now prevents us from calling it on an array with concrete type elements that conform to P. We could solve this by just defining an additional extension for when Element : P, and just forward onto the == P extension:
extension Array where Element : P {
func test<T>() -> [T] {
return (self as [P]).test()
}
}
let arr = [S()]
let result: [S] = arr.test()
However it's worth noting that this will perform an O(n) conversion of the array to a [P], as each element will have to be boxed in an existential container. If performance is an issue, you can simply solve this by re-implementing the extension method. This isn't an entirely satisfactory solution – hopefully a future version of the language will include a way to express a 'protocol type or conforms to protocol type' constraint.
Prior to Swift 3.1, the most general way of achieving this, as Rob shows in his answer, is to simply build a wrapper type for a [P], which you can then define your extension method(s) on.
Passing a protocol-typed instance to a constrained generic placeholder
Consider the following (contrived, but not uncommon) situation:
protocol P {
var bar: Int { get set }
func foo(str: String)
}
struct S : P {
var bar: Int
func foo(str: String) {/* ... */}
}
func takesConcreteP<T : P>(_ t: T) {/* ... */}
let p: P = S(bar: 5)
// error: Cannot invoke 'takesConcreteP' with an argument list of type '(P)'
takesConcreteP(p)
We cannot pass p to takesConcreteP(_:), as we cannot currently substitute P for a generic placeholder T : P. Let's take a look at a couple of ways in which we can solve this problem.
1. Opening existentials
Rather than attempting to substitute P for T : P, what if we could dig into the underlying concrete type that the P typed value was wrapping and substitute that instead? Unfortunately, this requires a language feature called opening existentials, which currently isn't directly available to users.
However, Swift does implicitly open existentials (protocol-typed values) when accessing members on them (i.e it digs out the runtime type and makes it accessible in the form of a generic placeholder). We can exploit this fact in a protocol extension on P:
extension P {
func callTakesConcreteP/*<Self : P>*/(/*self: Self*/) {
takesConcreteP(self)
}
}
Note the implicit generic Self placeholder that the extension method takes, which is used to type the implicit self parameter – this happens behind the scenes with all protocol extension members. When calling such a method on a protocol typed value P, Swift digs out the underlying concrete type, and uses this to satisfy the Self generic placeholder. This is why we're able to call takesConcreteP(_:) with self – we're satisfying T with Self.
This means that we can now say:
p.callTakesConcreteP()
And takesConcreteP(_:) gets called with its generic placeholder T being satisfied by the underlying concrete type (in this case S). Note that this isn't "protocols conforming to themselves", as we're substituting a concrete type rather than P – try adding a static requirement to the protocol and seeing what happens when you call it from within takesConcreteP(_:).
If Swift continues to disallow protocols from conforming to themselves, the next best alternative would be implicitly opening existentials when attempting to pass them as arguments to parameters of generic type – effectively doing exactly what our protocol extension trampoline did, just without the boilerplate.
However note that opening existentials isn't a general solution to the problem of protocols not conforming to themselves. It doesn't deal with heterogenous collections of protocol-typed values, which may all have different underlying concrete types. For example, consider:
struct Q : P {
var bar: Int
func foo(str: String) {}
}
// The placeholder `T` must be satisfied by a single type
func takesConcreteArrayOfP<T : P>(_ t: [T]) {}
// ...but an array of `P` could have elements of different underlying concrete types.
let array: [P] = [S(bar: 1), Q(bar: 2)]
// So there's no sensible concrete type we can substitute for `T`.
takesConcreteArrayOfP(array)
For the same reasons, a function with multiple T parameters would also be problematic, as the parameters must take arguments of the same type – however if we have two P values, there's no way we can guarantee at compile time that they both have the same underlying concrete type.
In order to solve this problem, we can use a type eraser.
2. Build a type eraser
As Rob says, a type eraser, is the most general solution to the problem of protocols not conforming to themselves. They allow us to wrap a protocol-typed instance in a concrete type that conforms to that protocol, by forwarding the instance requirements to the underlying instance.
So, let's build a type erasing box that forwards P's instance requirements onto an underlying arbitrary instance that conforms to P:
struct AnyP : P {
private var base: P
init(_ base: P) {
self.base = base
}
var bar: Int {
get { return base.bar }
set { base.bar = newValue }
}
func foo(str: String) { base.foo(str: str) }
}
Now we can just talk in terms of AnyP instead of P:
let p = AnyP(S(bar: 5))
takesConcreteP(p)
// example from #1...
let array = [AnyP(S(bar: 1)), AnyP(Q(bar: 2))]
takesConcreteArrayOfP(array)
Now, consider for a moment just why we had to build that box. As we discussed early, Swift needs a concrete type for cases where the protocol has static requirements. Consider if P had a static requirement – we would have needed to implement that in AnyP. But what should it have been implemented as? We're dealing with arbitrary instances that conform to P here – we don't know about how their underlying concrete types implement the static requirements, therefore we cannot meaningfully express this in AnyP.
Therefore, the solution in this case is only really useful in the case of instance protocol requirements. In the general case, we still cannot treat P as a concrete type that conforms to P.
EDIT: Eighteen more months of working w/ Swift, another major release (that provides a new diagnostic), and a comment from #AyBayBay makes me want to rewrite this answer. The new diagnostic is:
"Using 'P' as a concrete type conforming to protocol 'P' is not supported."
That actually makes this whole thing a lot clearer. This extension:
extension Array where Element : P {
doesn't apply when Element == P since P is not considered a concrete conformance of P. (The "put it in a box" solution below is still the most general solution.)
Old Answer:
It's yet another case of metatypes. Swift really wants you to get to a concrete type for most non-trivial things. [P] isn't a concrete type (you can't allocate a block of memory of known size for P). (I don't think that's actually true; you can absolutely create something of size P because it's done via indirection.) I don't think there's any evidence that this is a case of "shouldn't" work. This looks very much like one of their "doesn't work yet" cases. (Unfortunately it's almost impossible to get Apple to confirm the difference between those cases.) The fact that Array<P> can be a variable type (where Array cannot) indicates that they've already done some work in this direction, but Swift metatypes have lots of sharp edges and unimplemented cases. I don't think you're going to get a better "why" answer than that. "Because the compiler doesn't allow it." (Unsatisfying, I know. My whole Swift life…)
The solution is almost always to put things in a box. We build a type-eraser.
protocol P { }
struct S: P { }
struct AnyPArray {
var array: [P]
init(_ array:[P]) { self.array = array }
}
extension AnyPArray {
func test<T>() -> [T] {
return []
}
}
let arr = AnyPArray([S()])
let result: [S] = arr.test()
When Swift allows you to do this directly (which I do expect eventually), it will likely just be by creating this box for you automatically. Recursive enums had exactly this history. You had to box them and it was incredibly annoying and restricting, and then finally the compiler added indirect to do the same thing more automatically.
If you extend CollectionType protocol instead of Array and constraint by protocol as a concrete type, you can rewrite the previous code as follows.
protocol P { }
struct S: P { }
let arr:[P] = [ S() ]
extension CollectionType where Generator.Element == P {
func test<T>() -> [T] {
return []
}
}
let result : [S] = arr.test()

Swift 3 - How to verify class type of object

This line of code used to work with Swift 2, but now is incorrect in Swift 3.
if gestureRecognizer.isMember(of: UITapGestureRecognizer) { }
I get this error: Expected member name or constructor call after type name.
What is the correct way to use isMember(of:)?
Most likely, you'll want to not only check the type, but also cast to that type. In this case, use:
if let gestureRecognizer as? UITapGestureRecognizer { }
else { /* not a UITapGestureRecognizer */ }
Swift casting operators
These operators are only available in Swift, but still work when dealing with Objective C types.
The as operator
The as operator performs a cast when it is known at compile time that the cast always succeeds, such as upcasting or bridging. Upcasting lets you use an expression as an instance of its type’s supertype, without using an intermediate variable.
This is the most preferable operator to use, when possible. It guarentees success, without worrying about unwrapping an optional or risking a crash.
The as? operator
The as? operator performs a conditional cast of the expression to the specified type. The as? operator returns an optional of the specified type. At runtime, if the cast succeeds, the value of expression is wrapped in an optional and returned; otherwise, the value returned is nil. If casting to the specified type is guaranteed to fail or is guaranteed to succeed, a compile-time error is raised.
This is the second most preferable operator to use. Use it to safely handle the case in which a casting operator can't be performed.
The as! operator
The as! operator performs a forced cast of the expression to the specified type. The as! operator returns a value of the specified type, not an optional type. If the cast fails, a runtime error is raised. The behavior of x as! T is the same as the behavior of (x as? T)!.
This is the least preferable operator to use. I strongly advise against abusing it. Attempting to cast an expression to an incompatible type crashes your program.
Swift type checking
If you merely want to check the type of an expression, without casting to that type, then you can use these approaches. They are only available in Swift, but still work when dealing with Objective C types.
The is operator
The is operator checks at runtime whether the expression can be cast to the specified type. It returns true if the expression can be cast to the specified type; otherwise, it returns false
Works on any Swift type, including Objective C types.
Swift equivalent of isKind(of:)
Using type(of:)
Unlike the is operator, this can be used to check the exact type, without consideration for subclasses.
Can be used like: type(of: instance) == DesiredType.self
Swift equivalent of isMember(of:)
Legacy (Objective C) methods for checking types
These are all methods on NSObjectProtocol. They can be used in Swift code, but they only apply work with classes that derive from NSObjectProtocol (such as subclasses of NSObject). I advise against using these, but I mention them here for completeness
isKind(of:)
Returns a Boolean value that indicates whether the receiver is an instance of given class or an instance of any class that inherits from that class
Avoid this in Swift, use is operator instead.
isMember(of:)
Returns a Boolean value that indicates whether the receiver is an instance of a given class
Avoid this in Swift, use type(of: instance) == DesiredType.self instead.
conforms(to:)
Returns a Boolean value that indicates whether the receiver conforms to a given protocol.
Avoid this in Swift, use is operator instead.
There are several ways to check the class of an object. Most of the time you will want to use either the is or the as? operators like so:
let gestureRecognizer: UIGestureRecognizer = UITapGestureRecognizer()
// Using the is operator
if gestureRecognizer is UITapGestureRecognizer {
// You know that the object is an instance of UITapGestureRecognizer,
// but the compiler will not let you use UITapGestureRecognizer specific
// methods or properties on gestureRecognizer because the type of the
// variable is still UIGestureRecognizer
print("Here")
}
// Using the as? operator and optional binding
if let tapGestureRecognizer = gestureRecognizer as? UITapGestureRecognizer {
// tapGestureRecognizer is the same object as gestureRecognizer and is
// of type UITapGestureRecognizer, you can use UITapGestureRecognizer
// specific methods or properties.
print("Here")
}
// Using the type(of:) global function
if type(of: gestureRecognizer) == UITapGestureRecognizer.self {
// gestureRecognizer is an instance of UITapGestureRecognizer, but not any
// of its subclasses (if gestureRecognizer was an instance of a subclass of
// UITapGestureRecognizer, the body of this if would not execute).
// This kind of check is rarely usefull, be sure this is really what you
// want to do before you use it.
print("Here")
}
// Using the isKind(of:) method
if gestureRecognizer.isKind(of: UITapGestureRecognizer.self) {
// Like for the is operator, you know that the object is an instance of
// UITapGestureRecognizer (or any subclass of UITapGestureRecognizer).
// This is the Objective-C version of the is operator and will only work
// on classes that inherit from NSObject, don't use it in Swift.
print("Here")
}
// Using the isMember(of:) method
if gestureRecognizer.isMember(of: UITapGestureRecognizer.self) {
// gestureRecognizer is an instance of UITapGestureRecognizer, but not
// any of its subclasses.
// This is the Objective-C version of type(of:) and will only work on
// classes that inherit from NSObject, don't use it in Swift.
print("Here")
}
You have to use .self to refer the class type now.
let a = UITapGestureRecognizer()
print (a.isMember(of: UIGestureRecognizer.self))
There is also:
print (a is UITapGestureRecognizer)
Swift 3:
if gestureRecognizer is UITapGestureRecognizer {
//It's a tap
}

Cannot convert value of type 'Option' to expected argument type '#noescape (Option) throws -> Bool'

I have a class called Option. This is a Realm object so it's a subclass of Realm's own base class Object.
In a view controller I have an array property that holds a bunch of Option objects.
private var options = [Option]()
In a method down the view controller, I need to check if a certain Option object is contained within the aforementioned options array.
Previously (Swift 1.2), I have the checking logic like this.
func itemSelected(selection: Object) {
let option = selection as! Option
if !contains(options, option) {
// act accordingly
}
}
Now I'm converting the project to Swift 2 (I have updated the Realm's version to Swift 2 version as well). I updated the code to this.
func itemSelected(selection: Object) {
let option = selection as! Option
if !options.contains(option) {
// act accordingly
}
}
But now I'm getting the following compile error!
Cannot convert value of type 'Option' to expected argument type '#noescape (Option) throws -> Bool'
I can't figure out why. Any ideas?
This is because the contains function now expects a closure rather than an element on all non-equatable types. All you need to do is change it to the following
if !(options.contains{$0==option}) {
// act accordingly
}
What this does is it passes a closure in to the function, which returns true only if that closure satisfies any of its elements. $0 stands for the current element in the array that the contains function is testing against, and it returns true if that element is equal to the one that you are looking for.
While the first answer, that indicates this issue occurs because the contains method needs to operate on an Equatable type, is true, that's only half the story. The Realm Object class inherits NSObject, which conforms to Equatable (thus this should work without a closure). For more discussion on this, you can refer to this issue on the Realm GitHub page: https://github.com/realm/realm-cocoa/issues/2519. The Realm developers indicate that they believe this is a bug in Swift.
Ultimately, the suggested workaround is to re-declare the conformance to Equatable and Hashable, like so (this is copied verbatim from GitHub user bdash's comment on the previously posted issue):
public class A: Object, Equatable, Hashable {
}
public func ==(lhs: A, rhs: A) -> Bool {
return lhs.isEqual(rhs)
}
You'd replace the all instances of type A with type Option in that sample.
I've tested this solution, and it works for me in XCode 7.2.1, using Swift version 2.1.1.

initializing class properties before use in Swift/iOS

I'm having trouble grasping the proper way of instantiating variables that always need to be set before an object is fully functional but may need to be instantiated after the constructor. Based on Swift's other conventions and restrictions it seems like there is a design pattern I'm unaware of.
Here is my use case:
I have a class that inherits from UIViewController and will programmatically create views based on user actions
I need to attach these views to this class, but to do so I need to retrieve their content based on configuration data supplied by another controller
I don't care if this configuration data is passed to the constructor (in which case it would always be required) or supplied by a secondary call to this object before it is used
My problem seems to be that both of the approaches in bullet 3 seem flawed.
In the first case, there is only one legitimate constructor this class can be called with, yet I'm forced to override other constructors and initialize member variables with fake values even if the other constructors are never intended to be used (I'm also trying to keep these variables as let types based on Swift's best practices).
In the second case, I'm effectively splitting my constructor into two parts and introduce an additional point of failure in case the second part fails to be called prior to class being used. I also can't move this second part to a method that's guaranteed to be called prior to usage (such as viewDidLoad) because I still need to pass in additional arguments from the config. While I can make sure to call the initPartTwo manually, I'd prefer to have a mechanism that better groups it with the actual constructor. I can't be the first one to run into this and it seems like there is a pattern I'm not seeing to make this cleaner.
UPDATE:
I ended up going with a modified version of the pattern matt suggested:
struct Thing {
let item1: String
let item2: String
struct Config {
let item3: String
let item4: String
}
var config:Config! {
willSet {
if self.config != nil {
fatalError("tried to initialize config twice")
}
}
}
init() {
self.item1 = ...
self.item2 = ...
...
}
public func phaseTwoInit(item3: String, item4: String) {
self.item3 = item3
self.item4 = item4
...
}
}
var t = Thing()
...
t.phaseTwoInit(...)
...
// start using t
If an initial instance variable property value can't be supplied at object initialization time, the usual thing is to declare it as an Optional. That way it doesn't need to be initialized by the class's initializers (it has a value - it is nil automatically), plus your code subsequently can distinguished uninitialized (nil) from initialized (not nil).
If the Optional if an implicitly unwrapped Optional, this arrangement need have no particular effect on your code (i.e. it won't have to be peppered with unwrappings).
If your objection is that you are forced to open the door to multiple settings of this instance variable because now it must be declared with var, then close the door with a setter observer:
struct Thing {
var name:String! {
willSet {
if self.name != nil {
fatalError("tried to set name twice")
}
}
}
}
var t = Thing()
t.name = "Matt" // no problem
t.name = "Rumplestiltskin" // crash

how do you return nil if a certain type is passed to a function in Swift?

ok so I am trying to return nil if a certain type is passed into my function. In this case im passing in an instance of my class "BlogPost" and a type within this blogpost. I also have an array called "types" and I have assigned the variable Videos to the last index of that array. If this type is passed into my function I would like to return nil (so assuming im going to need an optional here for returning a possible nil) this is what I have so far :-
so all in all I need to pass in an instance of my blog post but always return nil if a certain type is passed in. Hope this makes sense
Update:
The types array is defined as follows:
let types : [String] = ["technology", "Fashion", "Animals"]
this is the array I am referring to in the function. Basically if that last entry of the array is entered into the function I need to return nil
sure this is blogpost it does actually have an empty string for type
great so im getting there what Ive done now is change the blogpost.type to choose one at random. So now if the specfic type is chosen from this array how would I do that still getting an error. This is what I have updated to
so now all I need to do is access the 2 type in that array and if I do access it return nil. Any thoughts on that? so to drag it on thanks
I don't think you can. You can create failable initialisers which does what you need but you cannot use it with normal function.
The best solution for you would be return optional Int or String and when you call the function just check the result for nil and do what you need to do, otherwise ignore it:
func randomViews(blog : BlogPost.Type) -> Int? {
case 10:
return nil
case 10, 20 :
return 0
default:
random
}
if (randomViews(parameter) == nil) {
//function returned nil
}
You have displayed error because you compare optional blog to Videos, you have to unwrap it first, for example if you are sure the blog has always have a value use:
if blog! == Videos
if not sure is safer to use:
if let blg = blog {
if blg == Videos {
}
else {
// blog has not have a value
}
You are passing blog as a BlogPost.Type parameter. That is not correct. You should have either just passed it the String parameter, or you could pass it the BlogPost itself:
func randomViews(blog: BlogPost) {
let videos = types[2]
if blog.type == videos {
// do whatever you want
}
// carry on
}
Unrelated to your question at hand, but notice that I use let instead of var when defining videos. Always use let if the value will not (and cannot) change.
Also note that I use lowercase letter v in videos, because Cocoa naming conventions dictate that variables generally start with lowercase letters, whereas types, classes, structs, and enums generally start with uppercase letters.

Resources