On page 17 of this WWDC14 presentation, it says
Working with Objective-C? Still have to manage autorelease pools
autoreleasepool { /* code */ }
What does that mean? Does it mean that if my code base doesn't have any Objective-C files, autoreleasepool {} is unnecessary?
In an answer of a related question, there is an example where autoreleasepool can be useful:
- (void)useALoadOfNumbers {
for (int j = 0; j < 10000; ++j) {
#autoreleasepool {
for (int i = 0; i < 10000; ++i) {
NSNumber *number = [NSNumber numberWithInt:(i+j)];
NSLog(#"number = %p", number);
}
}
}
}
If the code above gets translated into Swift with autoreleasepool dropped, will Swift be smart enough to know that the number variable should be released after the first } (like some other languages does)?
The autoreleasepool pattern is used in Swift when returning autorelease objects (created by either your Objective-C code or using Cocoa classes). The autorelease pattern in Swift functions much like it does in Objective-C. For example, consider this Swift rendition of your method (instantiating NSImage/UIImage objects):
func useManyImages() {
let filename = pathForResourceInBundle
for _ in 0 ..< 5 {
autoreleasepool {
for _ in 0 ..< 1000 {
let image = NSImage(contentsOfFile: filename)
}
}
}
}
If you run this in Instruments, you'll see an allocations graph with 5 small hills (because outer for-loop), like the following:
But if you do it without the autorelease pool, you'll see that peak memory usage is higher:
The autoreleasepool allows you to explicitly manage when autorelease objects are deallocated in Swift, just like you were able to in Objective-C.
Note: When dealing with Swift native objects, you generally will not receive autorelease objects. This is why the presentation mentioned the caveat about only needing this when "working with Objective-C", though I wish Apple was more clear on this point. But if you're dealing with Objective-C objects (including Cocoa classes), they may be autorelease objects, in which case this Swift rendition of the Objective-C #autoreleasepool pattern is still useful.
If you would use it in the equivalent Objective-C code, then you would use it in Swift.
will Swift be smart enough to know that the number variable should be
released after the first }
Only if Objective-C does. Both operate along the Cocoa memory management rules.
Of course ARC knows that number goes out of scope at the end of that iteration of the loop, and if it retained it, it will release it there. However, that does not tell you whether the object was autoreleased, because -[NSNumber numberWithInt:] may or may not have returned an autoreleased instance. There is no way you can know, because you don't have access to the source of -[NSNumber numberWithInt:].
#autoreleasepool can be used in Objective-C and Swift code to guarantee working with Objective-C code which relies on autorelease
[Under the hood]
Related
Was trying to fix a 300MB memory-leak, and after finding leak-reason;
(Which was calls to NSString's stringFromUTF8String:, from C++ thread (without #autoreleasepool-block wrapper))
I edited the code, to enforce reference-counting (instead of auto-release), something like below:
public func withNSString(
_ chars: UnsafePointer<Int8>,
_ callback: (NSString) -> Void
) {
let result: NSString = NSString(utf8String: chars)!;
callback(result);
}
As personal policy, with a Unit-Test, like:
import Foundation
import XCTest
#testable import MyApp
class AppTest: XCTestCase {
func testWithNSString_hasNoMemoryLeak() {
weak var weakRef: NSString? = nil
autoreleasepool {
let chars = ("some data" as NSString).utf8String!;
withNSString(chars, { strongRef in
weakRef = strongRef;
XCTAssertNotNil(weakRef);
})
// Checks if reference-counting is used.
XCTAssertNil(weakRef); // Fails, so no reference-counting.
}
// Checks if autoreleased.
XCTAssertNil(weakRef); // Fails, OMG! what is this?
}
}
But now, not even auto-release seems to work anymore (-_- )
Why does last XCTAssertNil call fail?
(In other words, how can I fix memory-leaks?)
The problem is that you're using a very short string. It's getting inlined onto the stack, so it's not released until the entire stack frame goes out of scope. If you made the string a little bit longer (2 characters longer), this would behave the way you expect. This is an implementation detail, of course, and could change due to different versions of the compiler, different versions of the OS, different optimization settings, or different architectures.
Keep in mind that testing this kind of thing with static strings of any kind can be tricky, since static strings are placed into the binary. So if the compiler notices that you've indirectly made a pointer to a static string, then it might optimize out the indirection and not release it.
In none of these cases is there a memory leak, though. Your memory leak is more likely in the calling code of withNSString. I would mostly suspect that you're not properly dealing with the bytes passed as chars. We would need to see more about why you think there's a leak to evaluate that. (Foundation also has some small leaks, and Instruments has false positives on leaks, so if you're chasing an allocation that is smaller than 50 bytes and doesn't recur on every operation, you probably are chasing ghosts.)
Note that this is a bit dangerous:
let chars = ("some data" as NSString).utf8String!
withNSString(chars, { strongRef in
The utf8String inner pointer is not promised to live longer than the NSString, and Swift is free to destroy objects after their last reference (which may be before they go out of scope). As the docs note:
This C string is a pointer to a structure inside the string object, which may have a lifetime shorter than the string object and will certainly not have a longer lifetime. Therefore, you should copy the C string if it needs to be stored outside of the memory context in which you use this property.
In this case the object is a constant string, which is in the binary and cannot be destroyed. But in more general cases this is is a classic cause of crashes. I would highly recommend moving away from the NSString interfaces and using String. It offers utf8CString, which returns a proper ContinguousArray, which is much safer.
let chars = "some data".utf8CString
chars.withUnsafeBufferPointer { buffer in
withNSString(buffer.baseAddress!, { strongRef in
weakRef = strongRef;
XCTAssertNotNil(weakRef);
})
}
withUnsafeBufferPointer ensures that chars cannot be destroyed before the block completes.
You can also ensure the lifetime of the string if needed (this is mostly useful for fixing older code you don't want to rewrite in safer ways):
let string = "some data"
withExtendedLifetime(string) {
let chars = string.utf8CString
chars.withUnsafeBufferPointer { buffer in
withNSString(buffer.baseAddress!, { strongRef in
weakRef = strongRef;
XCTAssertNotNil(weakRef);
})
}
}
On page 17 of this WWDC14 presentation, it says
Working with Objective-C? Still have to manage autorelease pools
autoreleasepool { /* code */ }
What does that mean? Does it mean that if my code base doesn't have any Objective-C files, autoreleasepool {} is unnecessary?
In an answer of a related question, there is an example where autoreleasepool can be useful:
- (void)useALoadOfNumbers {
for (int j = 0; j < 10000; ++j) {
#autoreleasepool {
for (int i = 0; i < 10000; ++i) {
NSNumber *number = [NSNumber numberWithInt:(i+j)];
NSLog(#"number = %p", number);
}
}
}
}
If the code above gets translated into Swift with autoreleasepool dropped, will Swift be smart enough to know that the number variable should be released after the first } (like some other languages does)?
The autoreleasepool pattern is used in Swift when returning autorelease objects (created by either your Objective-C code or using Cocoa classes). The autorelease pattern in Swift functions much like it does in Objective-C. For example, consider this Swift rendition of your method (instantiating NSImage/UIImage objects):
func useManyImages() {
let filename = pathForResourceInBundle
for _ in 0 ..< 5 {
autoreleasepool {
for _ in 0 ..< 1000 {
let image = NSImage(contentsOfFile: filename)
}
}
}
}
If you run this in Instruments, you'll see an allocations graph with 5 small hills (because outer for-loop), like the following:
But if you do it without the autorelease pool, you'll see that peak memory usage is higher:
The autoreleasepool allows you to explicitly manage when autorelease objects are deallocated in Swift, just like you were able to in Objective-C.
Note: When dealing with Swift native objects, you generally will not receive autorelease objects. This is why the presentation mentioned the caveat about only needing this when "working with Objective-C", though I wish Apple was more clear on this point. But if you're dealing with Objective-C objects (including Cocoa classes), they may be autorelease objects, in which case this Swift rendition of the Objective-C #autoreleasepool pattern is still useful.
If you would use it in the equivalent Objective-C code, then you would use it in Swift.
will Swift be smart enough to know that the number variable should be
released after the first }
Only if Objective-C does. Both operate along the Cocoa memory management rules.
Of course ARC knows that number goes out of scope at the end of that iteration of the loop, and if it retained it, it will release it there. However, that does not tell you whether the object was autoreleased, because -[NSNumber numberWithInt:] may or may not have returned an autoreleased instance. There is no way you can know, because you don't have access to the source of -[NSNumber numberWithInt:].
#autoreleasepool can be used in Objective-C and Swift code to guarantee working with Objective-C code which relies on autorelease
[Under the hood]
I've been saying this to form a C array of CGPoint:
let arr = UnsafeMutablePointer<CGPoint>.allocate(capacity:4)
defer {
arr.deinitialize()
arr.deallocate(capacity:4)
}
arr[0] = CGPoint(x:0,y:0)
arr[1] = CGPoint(x:50,y:50)
arr[2] = CGPoint(x:50,y:50)
arr[3] = CGPoint(x:0,y:100)
Now (Swift 4.1 in the Xcode 9.3 beta) both deinitialize and deallocate(capacity:) are deprecated. It looks like what I'm supposed to say now might be:
defer {
arr.deinitialize(count:4)
arr.deallocate()
}
Is that right?
Yes, that is part of SE-0184 Unsafe[Mutable][Raw][Buffer]Pointer: add missing methods, adjust existing labels for clarity, and remove deallocation size,
which has been implemented in Swift 4.1.
In particular:
Removing capacity from deallocate(capacity:) will end the confusion over what deallocate() does, making it obvious that deallocate() will free the entire memory block at self, just as if free() were called on it.
The old deallocate(capacity:) method should be marked as deprecated and eventually removed since it currently encourages dangerously incorrect code.
Could anyone please explain or give a link to a good guide on UnsafeMutablePointers? I can't freaking understand how they work and how to modify them.
Here's an example.
I am migrating my custom video player to Swift from Objective-C.
In Objective-C I create MTAudioProcessingTapRef using a callbacks structure:
MTAudioProcessingTapCallbacks callbacks;
callbacks.clientInfo = (__bridge void *)(self);
callbacks.init = initTap;
// Init other fields of callbacks
MTAudioProcessingTapCreate(kCFAllocatorDefault, &callbacks, kMTAudioProcessingTapCreationFlag_PostEffects, &tap);
Here I cast retainable MyClass pointer to void pointer to use it as clientInfo later.
(__bridge T) op casts the operand to the destination type T. If T is a
non-retainable pointer type, then op must have a retainable object
pointer type.
Then tap gets initialized:
void initTap(MTAudioProcessingTapRef tap, void *clientInfo, void **tapStorageOut)
{
*tapStorageOut = clientInfo;
}
Here I pass a pointer to self into tapStorageOut to grab self inside tap's callback function.
And then processing is performed:
void processTap(MTAudioProcessingTapRef tap, CMItemCount numberFrames, MTAudioProcessingTapFlags flags, AudioBufferList *bufferListInOut,
CMItemCount *numberFramesOut, MTAudioProcessingTapFlags *flagsOut)
{
MyClass *self = (__bridge MyClass *) MTAudioProcessingTapGetStorage(tap);
MTAudioProcessingTapGetSourceAudio(tap, numberFrames, bufferListInOut, flagsOut, NULL, numberFramesOut);
}
Now I have a few issues here.
I did found how to cast types into other types. Here are the functions:
func bridge<type : AnyObject>(object : type) -> UnsafeRawPointer
{
let unmanagedObject : Unmanaged = Unmanaged.passUnretained(object)
let unsafeMutableRawObject : UnsafeMutableRawPointer = unmanagedObject.toOpaque()
return UnsafeRawPointer(unsafeMutableRawObject)
}
func bridge<type : AnyObject>(pointer : UnsafeRawPointer) -> type
{
let unmanagedObject : Unmanaged<type> = Unmanaged<type>.fromOpaque(pointer)
let object : type = unmanagedObject.takeUnretainedValue()
return object
}
but I have zero understanding of what all of these letters do. Some explanation of this by one of you guys would be awesome.
Let's look at initTap function. Here I have a pointer A (tapStorageOut) that references a pointer B that references some data. I change pointer B to pointer C, which is my clientInfo. Clear as a sunny day.
Now, in Swift tapStorageOut is UnsafeMutablePointer now, whatever that thing is. And I have zero clue about how to deal with it.
In Objective-C when I process data I have a bufferListInOut variable which is a pointer to AudioBufferList structure.
In Swift however it has UnsafeMutablePointer type. So again, not understanding how UnsafeMutablePointers work prevents me from grabbing the data.
The main use of a pointer in Swift is working with C API and such. For the most part you should use reference semantics instead of pointers in Swift. That means using a class, when you pass a class instance around it automatically passes a reference instead of making a copy. Thus, it saves resources and any changes you make to a reference to the instance are reflected everywhere it is referenced. A Swift class is generally instantiated on the heap.
When you convert Objective-C to Swift pointers to objects are generally treated as references to those objects. Internally, a Swift reference is pretty much semantic sugar for a pointer.
Swift structures, on the other hand, have value semantics. They are generally instantiated on the stack and when you pass them around they are copied rather than passing a reference. The same goes when you mutate them, a new instance is created with the new values and it is swapped for the old instance. There are some tricks done where a struct will wrap a block of memory and hold a pointer to that memory. Thus a struct may have some reference semantics internally but try to avoid breaking the expectation of a struct's value being copied when it's passed around.
Some good reading:
Fundamentals of Callbacks for Swift Developers
Thinking in Swift, Part 3: Struct vs. Class
Lazy Initialization with Swift
I'd read these and take a good, hard look at your architecture before trying to use stuff like UnsafeMutablePointer. Yes, they are useful in some circumstances but they can be a pain to work with and are not necessary for most pure Swift tasks. Especially in a Swift API!
the operator "===" should compare class references to determine if both sides are referring same object:
var objectA : NSNumber = 1
var objectB : NSNumber = 1
print(objectA === objectB)
// return true,
so my question is NSNumber wrapped the object into the same object, how is the back-end logic of doing so.
NSNumber is one of a small handful of classes which can sometimes be represented as tagged pointers (at least on Apple platforms; I don't think this applies to the open-source version of (Core)Foundation).
Basically, this means that rather than a pointer to an actual instance of a class located elsewhere in memory, the NSNumber stores its value (in this case 1) directly inside the pointer. You can see this for yourself:
import Foundation
let x: NSNumber = 1
let y: NSNumber = 2
// Tagged pointers: the number is stored inside the pointer representation.
print(Unmanaged.passUnretained(x).toOpaque()) // 0x0000000000000137
print(Unmanaged.passUnretained(y).toOpaque()) // 0x0000000000000237
class C {}
let c = C()
// Not a tagged pointer; just a regular pointer to allocated memory.
print(Unmanaged.passUnretained(c).toOpaque()) // 0x00007fb32276daa0
The same optimizations can apply to NSString and other types too. For more details, read Mike Ash's excellent in-depth blog posts:
Friday Q&A 2012-07-27: Let's Build Tagged Pointers
Friday Q&A 2015-07-31: Tagged Pointer Strings
Don't rely on this, however. It's just an implementation detail, and not all NSNumbers may be represented this way. The correct way to compare them for equality is ==.