Check for value or reference type in Swift
AnyObject
is a protocol that any class type automatically conforms to, so you can write:
func isReferenceType(toTest: Any) -> Bool {
return toTest.dynamicType is AnyObject
}
class Foo { }
struct Bar { }
isReferenceType(Foo()) // true
isReferenceType(Bar()) // false
isReferenceType("foo") // false
isReferenceType(123) // false
isReferenceType([1,2,3]) // false
Is there a way to check if a delegate is a value or a reference type?
Every class conforms to the AnyClass
protocol. However enums and structs won't. Utilising that you can check if it's a class or a struct(or even an enum)
struct Test {
let delegate: Delegate
var isReferenceType: Bool {
return type(of:delegate) is AnyClass
}
}
Value type and reference type in Swift
First, NSString
is immutable, so although it is a reference type, it cannot be changed.
Now, when you say var str:NSString = "Hello, playground"
you are setting str
as a reference to a constant string "Hello, playground".
You then have var newStr = str
, so newStr
and str
will both refer to the same constant string.
Finally you have newStr = "hello"
, so newStr
now refers to a different constant string. At no time did you modify the original constant string "Hello, playground", and indeed you can't since it is both a constant and an immutable class.
If, however, you use an NSMutableString
and write:
var str:NSMutableString = NSMutableString(string:"Hello, playground")
var newStr = str
newStr.append(". Hello")
print(str)
print(newStr)
Then you will get the output
Hello, playground. Hello
Hello, playground. Hello
Since you are modifying the one object that is referenced by both variables.
How to get the reference of a value type in Swift?
There are several ways to get a reference. Kristopher's Box
solution is one of the most flexible, and can be built as a custom box to handle problems like passing structs to ObjC.
Beyond that, the most obvious is passing inout
parameters. This isn't precisely the same thing as a reference, but its behavior can be very similar, and definitely can be a part of high-performance code.
And moving down the stack there is UnsafePointer
and its friends, using withUnsafePointer(to:)
on general types, or .withUnsafeBufferPointer
on array types.
But if you need a persistent reference type that can be stored in a property, you'll need a Box
as Kristopher describes.
(Just to capture it for future readers since I hadn't remembered it, but MartinR pointed it out in a comment: as AnyObject
can automatically box value types.)
Is a protocol either a reference or value type in Swift?
I don't think this should increase the reference count:
var transferServiceScanner: TransferServiceScanner
increases the reference count to one, since all references are strong if they are not declared weak or sth else.
Storing the delegate variable as weak
makes sure strong references do not go both ways and so ARC can deinit them.
I'm trying to figure out if a class were to simply conform to a protocol, does this create a reference?
A class is always a reference-type, whether you refer to it through a protocol or directly. So assigning a protocol with a reference-type(class) behind it does not copy the class-object, but you rather give out another reference to the object and increases the reference-count which ARC looks at.
With
protocol TransferServiceScannerDelegateProtocol: NSObjectProtocol {
you are making sure, that only a class can implement the protocol, that is why you can declare weak var delegate: TransferServiceScannerDelegateProtocol
, because only classes can implement NSObjectProtocol
with NSObject
& co.
Without declaring a protocol class-only, either a struct or a class, both can implement the protocol. But only if you restrict the protocol to class-only can you use the protocol as if it were a class, using things like weak
with it.
Check if `Any` value is object
UPDATE
The code I have shown below is reported as not working in release build.
(Please see Paul Cantrell's comment below.)
Apologies for my "as far as I tested" was too limited.
I'll update this answer when I find some further info about this.
I'm not sure we can see this behaviour in the next beta (or GM or Released version...), but this works as you expect in Xcode 8 beta 6.
let foo: Any = 4
if type(of: foo) is AnyClass {
print("It's an object.")
let object = foo as AnyObject
//do something with `object` that requires reference semantics
} else {
print("It's not an object.") //->It's not an object.
}
class MyClass {}
let bar: Any = MyClass()
if type(of: bar) is AnyClass {
print("It's an object.") //->It's an object.
let object = foo as AnyObject
//do something with `object` that requires reference semantics
} else {
print("It's not an object.")
}
let baz: Any = Array<AnyObject>()
if type(of: baz) is AnyClass {
print("It's an object.")
let object = foo as AnyObject
//do something with `object` that requires reference semantics
} else {
print("It's not an object.") //->It's not an object.
}
I cannot check all possible cases, so there may be some edge cases where this does not work. But as far as I tested, this seems to work as expected.
Why Swift protocol conforming values are treated as Value types by default?
Your protocol SampleProtocol
could be adopted by a class
or a struct
. Swift is using the behavior of the value type which is the more restrictive type until you tell it that the protocol will only be used by a class
reference type.
Add conformance to AnyObject
to your protocol to get reference type behavior:
protocol SampleProtocol: AnyObject {
var message: String? { get set }
}
See The Swift 5.1 Programming Guide - Class-Only Protocols for more details.
The guide notes:
Use a class-only protocol when the behavior defined by that protocol’s
requirements assumes or requires that a conforming type has reference
semantics rather than value semantics.
Historical note: Using class
keyword:
Prior to Swift 4.0, this was written using the class
keyword:
protocol SampleProtocol: class {
var message: String? { get set }
}
This still works for the time being, but it is currently just a type alias for AnyObject
and will likely be removed in a later version of Swift.
is tuple a value type or reference type in Swift?
A simple test demonstrates that tuples are value types:
var tuple1 = (1, 2)
var tuple2 = tuple1
tuple1.0 = 3
print("t1 = \(tuple1), t2 = \(tuple2)")
Output:
t1 = (3, 2), t2 = (1, 2)
If tuples were reference types, tuple2
would have been changed.
Related Topics
Watchos3 Complication That Launches App
Is It Possible in Swift to Add Variables to an Object at Runtime
Convert Timestamp String with Epochal Time and Timezone into Nsdate
Swift Programming Nserrorpointer Error etc
Swift Error: Guard Body Must Not Fall Through
Swift Property Observer in Protocol Extension
Failed to Get Descriptors for Extensionbundleid
Add Custom Header to Collection View Swift
Weak VS Unowned in Swift. What Are the Internal Differences
What Is the "@Exported" Attribute in Swift
Po Swift String "Unresolved Identifier"
Delete All Characters After a Certain Character from a String in Swift
How to Repeat Animation (Using Uiviewpropertyanimator) Certain Number of Times
Swift - How to Create a View with a Shape Cropped in It
Swift 4 - Notification Center Addobserver Issue
iOS Tabbar Item Title Issue in iOS13