How to store CGContext state in a NSMutableArray? - objective-c

I am new to the CGContext world.
I need to create a stack of CGContext(s) in a NSMutableArray.
I have a valid PDFContext created with UIGraphicsBeginPDFContextToData
I'm passing this context to a method as an argument
-(void) drawTo:(CGContextRef) context{}
First I identify the current context with:
CGContextRef curCon = context;
NSLog value:
context:<CGContext 0x6b79d60>
Then I attempt to make a copy of the current context:
CGContextRef conCopy = UIGraphicsGetCurrentContext();
Then I add it to my NSMutableArray:
[myMutableArray* addObject:(id)conCopy];
Then I list the content of the NSMutableArray:
after an object added:<__NSArrayM 0x6b7e850>(<CGContext 0x6b79d60>)
And I see that the added value is the same context as originally sent to this method as an argument and not the copy.
What am I missing here ? Or perhaps it's not possible to store the status of current context in a NSMutableArray ? I understand that paths would not get saved, that's fine. I need to save anything and everything about the current context that can be saved.
Thank you!

You can't do this directly. But what's the real problem you're trying to solve? CGContextSaveGState() does what you're asking for, but only within the scope of the current context. CGLayer can effectively create contexts that you can carry around (though you still can't serialize them).
If your real goal is to save non-path state in a copyable form, then you can create a copyable object by calling all the CGContextGet... methods and storing their results. Then you can call CGContextSet... on them to make a new context. It's tedious, but should not be difficult. (Though it does raise the question of why. It feels like a very odd thing to be doing.)

UIGraphicsGetCurrentContext does no create a copy. The returned context is there one you created using UIGraphicsBeginPDFContextToData.

Related

Confusion with Passing Obj-C objects into methods and retaining the changes to that object

I'm writing a program and trying to learn more about threads, multiprocessing, and such.
My architecture is a Model/View/Controller type.
I have my own subclass of NSImageView (ThumbnailView) and I wanted to be clever and have it listen for a message to clear itself (so all the thumbnails just clear themselves without me having to loop through them).
The problem is my ThumbnailView is controlled by a ThumbnailViewController which is really the one listening for the message. When it gets the message it spins off a new thread with a class object that is the command (ClearThumbnailViewCommand). It passes as an argument a dictionary item containing the associated ThumbnailView object and a key. Within the ClearThumbnailViewCommand I set the image of the ThumbnailView object to be some neutral image (like gray.jpg).
All this works fine, however, the Thumbnail object that changed is not the same Thumbnail object that went in. So I figure I need to pass a pointer rather than the object. I remember something about using MyObject** as opposed to MyObject* and passing via &MyObject but I can't seem to untangle the various combinations. Not being able to reason it out I fell back to my, normally, foolproof system of trying random combinations of things but this time it's not helping.
It seems that even if I'm able to construct a class that passes a pointer (Not sure if I'm using these terms correctly), I'm not able to assign it correctly to the NSDictionary, which doesn't want an id** .
I'll try and include the basics below, if that helps at all.
ThumbnailVew : NSImageView {
ThumbnailVewController * _controller;
}
init {
_controller = [[ControllerClass alloc] initWithControlObject: &self];
}
ThumbnailVewController : ControllerClass {
id ** _controlObject;
}
initWithControlObject: (id**)object {
_controlObject = object;
}
Then when messages are posted a ThumbnailVewController method is called which ultimately does this…
Which, of course will not let me pass in &_controlObject
when it is all re-written so that I can pass _controlObject, I don't get an error, however the ThumbnailView I change is only local to the method.
if([command isEqualToString:#"CLEAR_THUMBNAILS"]) {
NSDictionary * dict;
dict = [[NSDictionary alloc] initWithObjectsAndKeys: &_controlObject, #"thumbnail", nil];
[self newThreadWithCommand:[[[ClearThumbnailViewCommand alloc] initWithArgument:dict] autorelease]];
}
Is this even possible?
Thanks for the feedback. I am indeed just trying to explore some various situations. I understand I may be going a round about way to get at some things but it does help me understand the boundaries more clearly.
In case it might help anyone else, I found a solution to my particular issue. As it turns out I was making the reference to the _controlObject in the init phase of the ThumbnailView. The object created during that phase is different than the ThumbnailView object created when awakeFromNib is called.
when I move the _controlObject assignment to the awakeFromNib method all works as I expected. (Of course I reset the code to not include any of the fancy ** and & declarations.
Again, thank you for helping me understand a bit more about this language. I'm starting to like it quite a bit.

awakeFromFetch with non-managed property

I have an NSManagedObject subclass with some image data in an NSData property (imageData), which is automatically persisted. After loading the data from the network I also set a custom NSImage property (image) with an image created from the data.
The problem is that if the object is a fault, awakeFromFetch is not called when I access the image property, since it is not handled by Core Data. I can of course override the image accessor and make sure the properties are loaded (by accessing imageData) but it would be nice if there was a way to have awakeFromFetch invoked as normal. Any suggestions?
As per TechZen's suggestion, I now execute the fetch request with returnsObjectsAsFaults set to NO. It's of course not ideal to pull all data from the cache each time the object is fetched, but in my case I always use the data immediately so it's acceptable.
You seem to want to do two contradictory things, you want the main entity to remain fault but be able to access its attributes. You cannot do that. A fault by definition has not attributes/properties because it is just a placeholder in the object graph. If you want your main object to remain a fault, you should move the UIImage to its own entity and link it to the main object. You should then be able to walk the object graph to obtain the UIImage without triggering the loading of the main object's fault placeholder.

How does NSValue do its magic?

I have an MVC application. The model has a property that is a struct NSSize. It is writable like this:
- (void)setSize:(NSSize)aSize;
The view sets this NSSize using key-value-coding. However, you can not key-value-code a struct, so I wrapped it in an NSValue-object like this:
[theView setValue:[NSValue valueWithSize:mySize]
forKey:#"theModel.size"];
To my understanding, this should not work since the accessor expects a struct and not an NSValue. But it works perfectly. Magically.
How is this possible?
Scroll down to "Wrapping and Unwrapping Structs", but here's the gist:
setValue:forKey: determines the data type required by the appropriate accessor or instance variable for the specified key. If the data type is not an object, then the value is extracted from the passed object using the appropriate -<type>Value method.
Btw, thanks for asking this question! This is one of those cocoa things that has always "just worked" and I never considered that it wasn't obvious how it was accomplished.

#property(copy) - is an entire copy being made?

I'm getting sublayers of a CALayer with this property accessor:
// #property(copy) NSArray *sublayers
NSArray* layer = mylayer.layer.sublayers;
Since this property uses "copy", every time I simply execute:
mylayer.layer.sublayers
is an entire copy of the sublayers array being made for me? If so that might be bad, because I could have one hundred+ layers, and definitely don't want to create a huge copy of them. I'm just looking to get a count and iterate through the existing layers, just a pointer to the existing layers,
Thank you
When you use the 'copy' declaration and you #synthesize the property, then copy is used when the property is set.
In your example, you are only accessing the value which just gives you a pointer to the sublayers array.
Here's a link to the ADC documentation on this point.
Update
IIRC, the runtime is smart enough to know if the object being set is mutable. If an immutable object is being passed in to the property it is retained and not copied.
In some cases, if you are passing in a mutable object that you want to be able to modify, then you should write your own setter that calls mutableCopy on the object. This is shown in the documentation link that I provided.
I'm not sure I understand your answer Abizern so let me say this:
If you use (copy) on a property you will be making a whole new copy of that object so would be wasting a lot of memory. I'm not sure why they are doing that, they could just use (readonly) instead if they want to protect the values from change. Plus remember most value classes are immutable in Obj-C so they can't change the value anyway.

wxWidgets using the 'new' keyword

For wxWidgets, why do you need to say:
MyFrame *frame = new MyFrame
instead of:
MyFrame frame;
What's the difference between the two? The second one is nicer to read and easier to use but all examples use the first so I wondered what the reason is.
Just to clarify, I know the second version doesn't work, but I'm wondering if there's a specific design decision which leads to having to use the first form instead of the second. TIA.
The first allocates a new MyFrame instance on the heap, and returns a pointer to it. The second creates a new MyFrame instance on the stack directly.
The reason you need to use the first syntax is that you will add this frame (UI element) into another UI element, such as a window. The window will take the pointer to a frame, and add it as a child.
If you use the second syntax, you'd have to pass a pointer to your stack object (&frame), which would compile, but then as soon as your method returned, frame's destructor would get called since frame would go out of scope. This would "break" the reference inside of your window.