Do protocols have an effect on the retain count?
I'm pretty sure that this is just Xcode getting confused. A protocol value shouldn't cause any extra retains over a normal strong reference, as memory management operations are forwarded to the underlying value through the type metadata stored within the existential container.
Here's a minimal example that reproduces the same result in Xcode's memory graph debugger:
protocol P {}
class C : P {
var d: D?
}
class D {
var p: P?
}
func foo() {
let c = C()
let d = D()
c.d = d
d.p = c
}
foo()
print("insert breakpoint V")
print("insert breakpoint ^")
If you insert a breakpoint between the print statements and look at the memory graph, you'll see 3 connections. Interestingly enough, if you assign c.d
after you assign d.p
, you'll see the correct result of 2 connections instead.
However if we set symbolic breakpoints on swift_retain
and swift_release
in order to see the strong retain/release Swift ARC traffic (while printing out the value stored in the %rdi
register, which appears to be the register used to pass the argument on x86):
and then insert a breakpoint immediately after the call to foo()
, we can see that in both cases the instances each get +2 retained and -2 released (bearing in mind they enter the world as +1 retained, thus keeping them allocated):
swift_retain 1
rdi = 0x000000010070fcd0
swift_retain 2
rdi = 0x000000010070fcd0
swift_release 1
rdi = 0x0000000000000000
swift_release 2
rdi = 0x000000010070fcd0
swift_retain 3
rdi = 0x00000001007084e0
swift_retain 4
rdi = 0x00000001007084e0
swift_release 3
rdi = 0x00000001007084e0
swift_release 4
rdi = 0x000000010070fcd0
swift_release 5
rdi = 0x00000001007084e0
So it looks like Xcode is at fault here, not Swift.
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.
Calling -retainCount Considered Harmful
The basics: What are the official reasons to not use retainCount?
Autorelease management is the most obvious -- you have no way to be sure how many of the references represented by the retainCount
are in a local or external (on a secondary thread, or in another thread's local pool) autorelease pool.
Also, some people have trouble with leaks, and at a higher level reference counting and how autorelease pools work at fundamental levels. They will write a program without (much) regard to proper reference counting, or without learning ref counting properly. This makes their program very difficult to debug, test, and improve -- it's also a very time consuming rectification.
The reason for discouraging its use (at the client level) is twofold:
The value may vary for so many reasons. Threading alone is reason enough to never trust it.
You still have to implement correct reference counting.
retainCount
will never save you from imbalanced reference counting.
Is there ever any situation at all when it might be useful?
You could in fact use it in a meaningful way if you wrote your own allocators or reference counting scheme, or if your object lived on one thread and you had access to any and all autorelease pools it could exist in. This also implies you would not share it with any external APIs. The easy way to simulate this is to create a program with one thread, zero autorelease pools, and do your reference counting the 'normal' way. It's unlikely that you'll ever need to solve this problem/write this program for anything other than "academic" reasons.
As a debugging aid: you could use it to verify that the retain count is not unusually high. If you take this approach, be mindful of the implementation variances (some are cited in this post), and don't rely on it. Don't even commit the tests to your SCM repository.
This may be a useful diagnostic in extremely rare circumstances. It can be used to detect:
Over-retaining: An allocation with a positive imbalance in retain count would not show up as a leak if the allocation is reachable by your program.
An object which is referenced by many other objects: One illustration of this problem is a (mutable) shared resource or collection which operates in a multithreaded context - frequent access or changes to this resource/collection can introduce a significant bottleneck in your program's execution.
Autorelease levels: Autoreleasing, autorelease pools, and retain/autorelease cycles all come with a cost. If you need to minimize or reduce memory use and/or growth, you could use this approach to detect excessive cases.
From commentary with Bavarious (below): a high value may also indicate an invalidated allocation (dealloc'd instance). This is completely an implementation detail, and again, not usable in production code. Messaging this allocation would result in a error when zombies are enabled.
What should be done instead?
If you're not responsible for returning the memory at self
(that is, you did not write an allocator), leave it alone - it is useless.
You have to learn proper reference counting.
For a better understanding of release and autorelease usage, set up some breakpoints and understand how they are used, in what cases, etc. You'll still have to learn to use reference counting correctly, but this can aid your understanding of why it's useless.
Even simpler: use Instruments to track allocs and ref counts, then analyze the ref counting and callstacks of several objects in an active program.
Historical/explanatory: Why does Apple provide this method in the NSObject protocol if it's not intended to be used? Does Apple's code rely on retainCount for some purpose? If so, why isn't it hidden away somewhere?
We can assume that it is public for two primary reasons:
Reference counting proper in managed environments. It's fine for the allocators to use
retainCount
-- really. It's a very simple concept. When-[NSObject release]
is called, the ref counter (unless overridden) may be called, and the object can be deallocated ifretainCount
is 0 (after calling dealloc). This is all fine at the allocator level. Allocators and zones are (largely) abstracted so... this makes the result meaningless for ordinary clients. See commentary with bbum (below) for details on whyretainCount
cannot be equal to 0 at the client level, object deallocation, deallocation sequences, and more.To make it available to subclassers who want a custom behavior, and because the other reference counting methods are public. It may be handy in a few cases, but it's typically used for the wrong reasons (e.g. immortal singletons). If you need your own reference counting scheme, then this family may be worth overriding.
For deeper understanding: What are the reasons that an object may have a different retain count than would be assumed from user code? Can you give any examples*** of standard procedures that framework code might use which cause such a difference? Are there any known cases where the retain count is always different than what a new user might expect?
Again, a custom reference counting schemes and immortal objects. NSCFString
literals fall into the latter category:
NSLog(@"%qu", [@"MyString" retainCount]);
// Logs: 1152921504606846975
Anything else you think is worth mentioning about retainCount?
It's useless as a debugging aid. Learn to use leak and zombie analyses, and use them often -- even after you have a handle on reference counting.
Update: bbum has posted an article entitled retainCount is useless. The article contains a thorough discussion of why -retainCount
isn’t useful in the vast majority of cases.
iOS: Reference counting
In lines 2, 3 and 4 you are affecting the instance variable tempArray
to the same object as myArray
. But if you write it this way, you try to affect an instance variable. As a matter of fact, if you didn't write any @synthesize tempArray
or @synthesize tempArray = tempArray
in your code, by default the instance variable generated automatically to store the property value is the same name as the property name, but prefixed with an underscore. So as the property name is tempArray
, the instance variable is named _tempArray
. The instance variable tempArray
itself does not exist and your line of code is invalid.
So if we suppose you wrote instead:
-(void) sampleFunction
{
NSArray *myArray = [[NSArray alloc] init]; // (1)
self.tempArray = myArray; // (2)
self.tempArray = myArray; // (3)
self.tempArray = [NSArray arrayWithObject:@"SomeString"]; // (4)
}
- In (1) you are creating a brand new instance of NSArray. "alloc" always initialize new instance with a reference count of 1
- In (2) you write
self.tempArray = myArray
(which is equivalent to[self setTempArray:myArray];
and thus call the property setter), so you set the property to point to the same array you created in (1). This array is thus retained by the property, and its retainCount increses by one, because it is retained bymyArray
and by theself.tempArray
property. In (3) you affect the property to the very same object as before. This the ref count does not change at all. You could understand that as if you replaced the value of the
self.tempArray
with another value, so the setter of the property release the old value (decrementing its ref count), then retain the new value (thus incrementing its ref count). As in your case the old and new values are the same object, you would decrement the ref count of your array then re-increment it again. In practice, the ref count does not even change at all (instead of decrementing+incrementing again) to avoid any potential dealloc of the object, because the default implementation of a property setter is as follow:-(void)setTempArray:(NSArray*)newValue
{
// check if old and new value are different. Only do sthg if they are different
if (newValue != _tempArray)
{
[_tempArray release]; // release old value
[newValue retain]; // retain new value
_tempArray = newValue; // store new value in the backing variable associated with the property
}
}In (4) you replace again the value of the property
tempArray
, but this time with a completely new object. So the property will release its old value and retain the new one. Thus the first array you created in (1) which had a refcount of 2 (retained bymyArray
and byself.tempArray
) decrease its ref count to 1 (because the property won't retain it anymore), and the new instance you created[NSArray arrayWithObject:@"SomeString"]
is retained by the property, so its ref count is +1.
If you replaced self.tempArray = ...
(so the use of the property) with the direct use of the instance variable, using instance variables don't retain the objects they are affected to (except if you are using ARC but it seems you don't), so the ref count of the object wouldn't have changed at all in (2), (3) and (4).
Does protocol array elements passed by value or reference?
Protocols should be seen as value types because you need to explicitly tell the compiler that it is a reference type by defining it as conforming to AnyObject (which all classes conform to)
So if you have
protocol ProtocolB: AnyObject
then any type conforming to ProtocolB will be sent by reference and otherwise not.
Here is a simplified example
protocol ProtocolA {
var x: Int { get set }
}
protocol ProtocolB: AnyObject {
var y: Int { get set }
}
class ClassA: ProtocolA, ProtocolB {
var x = 0
var y = 0
}
func exampleFunction(_ object: ProtocolA) {
object.x += 2 // <-- This will generate a compilation error
}
func exampleFunction(_ object: ProtocolB) {
object.y += 2 // This is fine
}
Swift Struct's Reference Count
Structures and enumerations have value-semantics. There is no notion of a reference count, because they are passed by copying. Their members may be pointers to reference-types, but the pointer itself is copied. As long as you don't have a reference-type in a structure, you don't need to worry about reference counting.
Sure, one may argue that Swift internally uses copy-on-write optimizations using reference-types disguised as structures (eg. Array
, Dictionary
etc.), but they implement value-semantics.
Related Topics
Swift: Mkannotation Long Title Text
How to Increment a Swift Int Enumeration
How to Use Nscalendar Range Function Within Calendar
Support Arkit in Lower End Devices
Assigning Values to Tuple in for Loop
Addperiodictimeobserver Is Not Called Every Millisecond
Comma Automatically Being Added to Textfield in Swift
How to Add UIpickerview in UIalertcontroller
Skease Action, How to Use Float Changing Action Setter Block
Images Being Flipped When Adding to Nsattributedstring
Geofire/Firebase Function Is Executing Handler Multiple Times in Swift
How to Save Re-Ordered Tableview Cells to Core Data
Add Catextlayer on Top of Nsimageview
Pie Chart Entries Outside Slices Have Different Position Offsets
Convert Ble Current Time to Date
Removing Scheduled Local Notification
Why Are Implicitly Unwrapped Variables Now Printing Out as Some(...) in Swift 4.1