When generating a CGImage one can choose between an initializer using JPEG-encoded data, PNG-encoded data or just data. I'm generating an image from a Data object containing 16 bit grayscale values.
The initializer required a CGDataProvider which could be Sequential-Access or Direct-Access Data Provider.
Under the Sequential-Access we have only one initializer:
Creates a sequential-access data provider
Under the Direct-Access we have multiple initializers but let's focus on a subset:
Creates a direct-access data provider
Creates a direct-access data provider that uses data your program supplies
Creates a data provider that reads from a CFData object
We can definitely notice that the last item in the Direct-Access list missing the "direct-access" term in its definition.
First question:
I understand the notion of sequential and direct access to memory, but can someone give me a more precise definition taking into consideration Swift's behaviour?
Let's move on.
I have two different Data objects in my subclass of UIViewController.
I'm calling from the main dispatch queue to a static function I have in a helper class.
This helper function gets the Data and this is where I'm creating the CGImage and return it to the view controller.
The view controller saves each image in a separate property variable.
This is where things get weird:
Using "Creates a data provider that reads from a CFData object" - works!
But I don't want to use CoreFoundation inside an iOS project and create a CFData object (which probably copies the buffer into a new one)
Using "Creates a direct-access data provider that uses data your program supplies" - works!
I'm accessing the raw buffer using withUnsafeBytes which provides me an UnsafeRawBufferPointer inside a closure.
But if I change the access to the Data using withUnsafeMutableBytes - the second image returned to the view controller overrides the first image!
I tried to debug it with XCode and each image is actually generated appropriately inside the helper function, but when the second image returned to the view controller, the first image is changed.
Second question:
What could create this weird behaviour?
There are a lot of participants in this process and I think I did everything I could to try and resolve it.
Any feedback would be kindly appreciated.
"Direct-access" just means all the bytes are always available, and you can access them in any order.
"Sequential-access" means that the bytes are in a stream, and you can only read them at the current "head", skip forward some number of bytes, or rewind all the way to the beginning. You can't just jump anywhere you want. For example, if you're streaming data from the network, you may never have all the data in memory at the same time.
CFData is always direct-access, so there is no need to call this out in the definition. Nothing here relates to Swift. These are all Core Foundation (i.e. "C") data structures. Swift can bridge Data to CFData, but these interfaces long predate Swift.
But I don't want to use CoreFoundation inside an iOS project and create a CFData object (which probably copies the buffer into a new one)
Data can bridge to CFData without copying. You just need to add as CFData. Data is a Foundation overlay for NSData, and NSData toll-free bridges to CFData.
let data = Data(...)
let source = CGImageSourceCreateWithData(data as CFData, nil)
To your question about the particular behavior, I'm sure you have a bug, but we'd have to see the code. If I had to guess, I'd suspect you're relying on object lifetimes that aren't promised. This is a common mistake when working with Unsafe types. But if you already have a Data, I wouldn't bother with custom CGImageSources. That's a lot of work that generally isn't needed if you already have all the data in memory. (If you still want to do that, post some code and I'm sure we can walk you through it. It's not that hard, it's just generally not necessary, and a bit fiddly in Swift.)
Related
I have an app that is storing some data using the Cocoa/ObjC initWithCoder / encodeWithCoder style marshaling. Over the life of the app one of the classes that has been removed is an NSDate+Utils category.
The question is - if an NSDate+Utils is serialized to disk, and then deserialized with a later codebase when NSDate+Utils no longer exists; will it come back as an NSDate, or will it crash??
It won't crash. You just need to check whether it's nil. If that' nil, then just skip it, otherwise populate the data to your property. By the way, there is nothing to do with the codebase. It's just whether that local data being stored in the device. Codes are just things that tell device what or how to do stuff.
I wrote a small program to test this. Categories seem to get written as the base class - I assume as long as they don't add fields and/or mess with the withCoder methods.
I am tying to understand the example in the apple docs for deep copying an array of dictionaries Here.
In Listing 3 A true deep copy
The example shows
NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:oldArray]];
Notice there is no copy, mutable copy , or autorelease operators, so I am struggling to understand how this is a copy and how it gets released. In fact, if I release my implementation, it will crash. It does however work as expected, and there does not appear to be any abandoned memory using it as the example shows.
I looked the the NSUnarchiver class reference and it mentions that the unarchiveObjectWithData method creates a temporary copy of the object(s)?
Does this mean the proper implementation then is to allocate and init the new array rather than just assigning the pointer so it can be released?
Thanks in advance.
They are doing a deep copy by doing a full archival pass on the object graph. Using NSArchiver enables things like automatic cyclic reference management and the objects can choose not to encode things like their delegate or they can hook stuff back up on unarchival.
For all intents and purposes, it is archival by saving something to disk and then reading it back in as a new document. Only, instead of the disk, it is just stored in memory all the time.
It is slow, very expensive, and totally inappropriate for anything but when you very occasionally need to duplicate a complex object graph completely.
unarchiveObjectWithData: returns an auto-released object. If you using MRC, you need to retain it if you want to keep it. But, a better solution would be to move to ARC.
You are crashing on retain (or shortly after) because you did not respect Apple's stated memory management rules, which can be found here: https://developer.apple.com/library/prerelease/ios/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html
Did you get the object from a method that contains alloc, new, copy or deepCopy in its name? No, then it is not your responsibility to release it.
Do you want to hold on to this object? If so, it is your responsibility to retain it.
As to why this code snippet results in a deep copy, you should read again what the archiver classes do. They don't deal with your objects, they deal with "descriptions of the contents of your objects". You might just as easily have done a "json import of the result of a json export" or an "xml import of an xml export".
I try to authenticate my app with Twitter with following code: pastebin
However, if I remove the (useless?) loop line 23ff
for (ACAccount *acc in arrayOfAccounts) {
[acc accountType].identifier;
//Otherwise the identifier get lost - god knows why -__-
}
the acc.type becomes (null) when it gets executed further in
AccountHandler checkAccountOf:acc. If I leave the loop in, the type is correctly set.
I am pretty sure it has to do with the fact that I am in a block and then move on to the main queue, but I am wondering if I am doing something wrong? This loop does not look like sth I am supposed to have to do.
Something kinda similar happened here.
ACAccounts are not thread safe. You should use them only on the thread that they originate. And for this purpose you can read 'thread' as 'queue'.
While I've not seen formal documentation of that, if you NSLog an account you'll see that it's a Core Data object and the lack of thread safety on Core Data objects is well documented.
The specific behaviour is that a Core Data object can be a fault. That means that what you're holding is a reference to the object but not the actual object. When you try to access a property the object will be loaded into memory.
What Core Data is doing underneath is caching things in memory and returning faults until it knows that an object is really needed. The efficient coordination of that cache is what limits individual instances of the Core Data object that coordinates objects to a single thread.
If you do the action that should bring the object into memory on the wrong thread — which is what happens when you access identifier here — then the behaviour is undefined. You could just get a nil result or you could crash your application.
(aside: the reason that Core Data works like this is that it stores an object graph, so possibly 1000s of interconnected objects, and you can traverse it just like any other group of objects. However you don't normally want to pay the costs associated with loading every single one of them into memory just to access whatever usually tiny subset of information you're going to use, so it needs a way of providing a normal Objective-C interface while lazily loading)
The code you've linked to skirts around that issue by ensuring that the objects are in the cache, and hence in memory, before queue hopping. So the 'fetch from store' step occurs on the correct queue. However the code is nevertheless entirely unsafe because objects may transition from being in memory back to being faults according to whatever logic Core Data cares to apply.
The author obviously thinks they've found some bug on Apple's part. They haven't, they've merely decided to assume something is thread safe when it isn't and have then found a way of relying on undefined behaviour that happened to work in their tests.
Moral of the story: keep the accounts themselves on a single thread. If you want to do some processing with the properties of an account then collect the relevant properties themselves as fundamental Foundation objects and post those off.
I'm designing a object persistent code.
IMO, memory snapshot is fastest, reliable and compact persistent method within a few limitation.
It's easy with C structs. I can layout all objects' memory layout manually. I can save all references as index of object collection. So reference is not a problem.
Anyway I want to try this with Objective-C objects. To do this, objects must be positioned in specific location of memory. So, if I can specify memory location of allocation, I can snapshot the memory. And when restoring, I can get an object at specific address.
Of course, all of these are machine-specific and needs many tricks, but it's fine to me.
The only problem is I don't know way to specify location of new Objective-C object. How can I do this?
Generally people use NSCoding and NSKeyedArchiver (or some custom subclass thereof). I think your C method would have worked before the 64-bit runtime, since the data part of objects was implemented using structs, but I think the new runtime's use of nonfragile instance variables would complicate matters. In any event, the program that loads the persistent objects still has to have the class definitions for them, either hard-coded or loaded via bundles.
Im learning how to do drag and drop to allow ordering of items in an NSOutlineView. (Its my first time using NSPasteboard).
From the slightly related examples I found online, it seems you use:
[pasteboard setData: data forType: #"myapptype"];
What should be put into the NSData when you are doing a move. The samples put an archived version of the object as the data.
The object attributes could possibly change while the item is being dragged, so doest it make sense that instead I stuff a pointer to the object in there?
No, you generally don't want to stuff a pointer to an object onto the pasteboard.
The pasteboard has to have (basically) one of two types of things on it: data, or a promise to provide the data when asked for it. The pasteboard's lifetime is potentially (and likely) far longer than the lifetime of your application. So imagine this scenario:
User copies some data. You put a pointer to your object on the drag.
User quits your program. Your object is deallocated.
User starts up another instance of your program and hits paste.
Likely outcome: you crash when the second instance of your program dereferences an invalid pointer.
What data actually needs to go on the pasteboard can be very specific to your program, but you generally speaking don't want to put 'live' data on there. It's in your best interests to archive. You may find NSCoder useful for doing simple archiving.
I will carve an exception here and say one could conceive of doing pointer stuff if it was only ever done for drag and drop (since I don't think you can do the drag without the program still running) and if you cleared the drag pasteboard when you quit the program. But it's not a best practice, and I would say that if you're not very experienced and very aware of the pitfalls, it's a risky technique.