2

I was doing some tests with pointers in Swift, and wanted to verify that the objects that I was taking pointers of were not being retained.

func test1(){
    let str = aaa();
    print(CFGetRetainCount(str))
    let ptr1 = Unmanaged.passUnretained(str).toOpaque()
    print(CFGetRetainCount(str))
    let str2 = Unmanaged<aaa>.fromOpaque(ptr1).takeUnretainedValue();
    print(CFGetRetainCount(str2))
}

The result is 2,2,3. So "passUnretained" did not retain, but "takeUnretainedValue" did.

Changing to "takeRetainedValue" fixes the issue, and causes the expected crash. Output 2,2,2.

func test1(){
    let str = aaa();
    print(CFGetRetainCount(str))
    let ptr1 = Unmanaged.passUnretained(str).toOpaque()
    print(CFGetRetainCount(str))
    let str2 = Unmanaged<aaa>.fromOpaque(ptr1).takeRetainedValue();
    print(CFGetRetainCount(str2))
}

So, to conclude, "takeRetainedValue" does NOT retain the value.

Update: I've edited this question to remove some previously confusing statements and returned it to a basic programming question.

user1122069
  • 1,767
  • 1
  • 24
  • 52
  • Yes. I figured out the initial issue. "passUnretained" does not retain, but "takeUnretainedValue" does. Yet these are not related pairs, but passUnretained (+0) is opposed by passRetained (+1). Do you think I should just delete this issue as there is no possible rationale or not a coding issue anymore? – user1122069 Jan 20 '17 at 22:34
  • I'm glad it makes sense for you. Not being sarcastic. It is important to understand what the terms mean in order to use them properly and to be able to review code. – user1122069 Jan 21 '17 at 00:03

1 Answers1

0

Actually, it turns out that "takeUnretainedValue" does not retain the value, rather it is done by the assignment itself after the value is returned.

I tested and found that as long as "passRetained" is used with "takeRetained" and "passUnretained" with "takeUnretained", then the variable does not leak, and it is just +1 due to the new variable added.

func test1() -> UnsafeMutableRawPointer {
    let str = aaa();
    print(CFGetRetainCount(str))
    let ptr1 = Unmanaged.passRetained(str).toOpaque()
    print(CFGetRetainCount(str))
    let str2 = Unmanaged<aaa>.fromOpaque(ptr1).takeRetainedValue();
    print(CFGetRetainCount(str2))
    print(str2);
    print("111");
    print(str.b)
    return ptr1;
}

let ptr4 = test1();
let str4 = Unmanaged<aaa>.fromOpaque(ptr4).takeUnretainedValue();
print(CFGetRetainCount(str4))
print(str4.b);

Here is a test showing that takeUnretainedValue does not increment the ref count (removed the assignment, but called the function anyway).

func test1() {
    let str = aaa();
    print(CFGetRetainCount(str))
    let ptr1 = Unmanaged.passUnretained(str).toOpaque()
    print(CFGetRetainCount(str))
    Unmanaged<aaa>.fromOpaque(ptr1).takeUnretainedValue();
    print(CFGetRetainCount(str))
    //print(str2);
    print("111");
    print(str.b)
}

Similar tests show that "takeRetainedValue" decrements the retain count. It is referring to the "extra retain" from passRetained, and returns the value as it was when it started. It is also then given +1 if assigned.

user1122069
  • 1,767
  • 1
  • 24
  • 52
  • The question is and was titled "Why does Swift “Managed.fromOpaque.takeUnretainedValue()” retain the value?". The fact of the matter is that takeUnretainedValue does not retain and hence the confusion. – user1122069 Jan 21 '17 at 01:21