Performance of cancelPreviousPerformRequests - objective-c

I use performSelector:withObject:afterDelay: to delay a layout operation so that it's not done multiple times. Normally, I do something like this (example only):
- (void) setViewNeedsLayout{
if (!_viewsNeedLayout){
_viewsNeedLayout = YES;
[self performSelector:#selector(layoutViews) withObject:nil afterDelay:0];
}
}
- (void) layoutViews{
_viewsNeedLayout = NO;
//layout views
}
It's pretty simple, efficient and effectively delays the layout operation until the end of the current run loop, but it does require that I keep track of the ivar: _viewsNeedLayout.
However, I'm wondering about the performance of cancelPreviousPerformRequestsWithTarget:selector:object:. Instead of using an iVar to keep track of whether I've kicked off the delayed selector, I'm wondering if it might be better to do something like this:
- (void) setViewNeedsLayout{
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(layoutViews) object:nil];
[self performSelector:#selector(layoutViews) withObject:nil afterDelay:0];
}
Now, the issue is how performant is cancelPreviousPerformRequestsWithTarget? In some cases, the respective setViewNeedsLayout method (or equivalent) could get called possibly hundreds of times... as an extreme example. But it is an easier way to deal with the delayed/queued method call so I'd prefer to use it if it's not going to have a significant impact on performance.

Related

awakeFromInsert called twice with nested contexts

This project uses Mogenerator and Magical Record. I have tracked down a bug to the fact that awakeFromInsert is getting called twice. Once for each of my contexts I presume. This is an issue because I need to listen for NSNotifications on this NSManagedObject like this:
- (void)awakeFromInsert
{
// Listen for a return from background mode
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(enteringForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];
}
But awakeFromInsert get's called twice which is rather annoying. I want to call a method ONCE when my NSManagedObject is first created.
After searching this solution seems to make a lot of sense. However I can't see how I can add a category onto NSManagedObject when using Mogenerator and MagicalRecord. Without some complex overriding.
In MagicalRecord MR_createEntity calls
if ([self respondsToSelector:#selector(insertInManagedObjectContext:)])
{
id entity = [self performSelector:#selector(insertInManagedObjectContext:) withObject:context];
return entity;
}
Is there a neater solution to this issue?
Ok well this feels very hacky but appears to work. I created the following class methods on my human readable NSManagedObject class:
+ (id)insertInManagedObjectContext:(NSManagedObjectContext*)moc_ {
JWBoard *newobject = [super insertInManagedObjectContext:moc_];
[JWBoard awakeFromCreate:newobject];
return newobject;
}
+ (void)awakeFromCreate:(JWBoard *)board
{
// do setup stuff & add observers
}
Open to much better solutions!
Open to much better solutions!
I wish! Would have been easy enough for apple to not invoke awakeFromInsert, or to at least provide a flag that's true in the context of a "parentProcessSaveRequest." If you look at the call stack for the not-first calls to awakeFromInsert, the stack always contains parentProcessSaveRequest.
Here's some terrible code proving as much:
- (void) awakeFromInsert
{
[super awakeFromInsert];
NSArray* stackArray = [NSThread callStackSymbols];
for (NSString* method in stackArray)
{
if ([method rangeOfString:#"_parentProcessSaveRequest"].location != NSNotFound)
{
NSLog(#"Parent insert %#",self.objectID);
return;
}
}
NSLog(#"First insert %#",self.objectID);
// Initialize here
}
And the log output -- the objectId stays the same:
2014-05-19 20:53:52.964 myApp[1891:a01f] First insert 0x6000000326c0 <x-coredata:///MyEntity/t496E9B17-E170-4A7C-B7D4-7D8B92433E1C2>
2014-05-19 20:53:53.531 myApp[1891:303] Parent insert 0xdca8000eb <x-coredata://7274869F-4BF3-4B8A-9270-A64E54476AAD/MyEntity/p14122>
2014-05-19 20:53:53.537 myApp[1891:303] Parent insert 0xdca8000eb <x-coredata://7274869F-4BF3-4B8A-9270-A64E54476AAD/MyEntity/p14122>
Seems to work for saving to any of the nested contexts that I have, ugly as it is.
Unfortunately I cant figure any reasonable way to determine whether awakeFromInsert is being called in the context of a parentProcessSaveRequest. Come on, Apple! Give us a flag here.
here is the simplest one:
when parentContext is null, means when this context is saved you can do you custom logic, for example incrementing table number
- (void)awakeFromInsert
{
if (!self.managedObjectContext.parentContext) {
//setting tableNumber
[self willChangeValueForKey:#"number"];
[self setPrimitiveNumber:tableNumber];
[self didChangeValueForKey:#"number"];
}
}

Concurrent drawRect:

I have a large array of objects (typically 500 - 2000) that render to the screen. Unfortunately, rendering is not exactly snappy at the moment.
Each object needs to perform some calculations which take up most of the time and finally draw itself to the screen, i.e. currently my drawRect: method looks essentially like this:
(I've left out trivial optimizations like checking bounding rects vs. dirtyRect for the sake of readability)
- (void)drawRect:(NSRect)dirtyRect
{
for (Thing *thing in [self getThings])
{
[thing prepareForDrawing];
[thing draw];
}
}
An obvious candidate for concurrent processing, right?
I couldn't come up with a good approach to decouple preparation from the actual drawing operations, i.e. perform the pre-processing in parallel and somehow queue the drawing commands until all processing is done, then render all in one go.
However, thinking of the goodness that is GCD I came up with the following scheme.
It kind of sounds OK to me but being new to GCD and before running into weird multi-threading issues four weeks after a public release or just using a bad GCD design pattern in general I thought I'd ask for feedback.
Can anybody see a problem with this approach - potential issues, or a better solution?
- (void)drawRect:(NSRect)dirtyRect
{
[[self getThings] enumerateObjectsWithOptions:NSEnumerationConcurrent
usingBlock:^(id obj, NSUInteger idx, BOOL *stop)
{
// prepare concurrently
Thing *thing = (Thing*)obj;
[thing prepareForDrawing];
// always draw in main thread
dispatch_async(dispatch_get_main_queue(), ^{
[thing draw];
});
}
}
That won't work because the invocations of [thing draw] will happen outside of -drawRect: after it has completed. The graphics context will no longer be valid for drawing into that view.
Why are the "things" not prepared in advance? -drawRect: is for drawing, not computation. Any necessary expensive computation should have been done in advance.

Reusing NSObjects by Overriding release in Obj-C

I am implementing an object reuse scheme using a singleton class.
What I do basically is:
MyClass* obj = [[MyClassBank sharedBank] getReusableItem];
The bank is just an NSMutableSet tweaked for optimum reusability. When I was happily implementing this Singleton, I had in mind that I will just do the following when I am done with "obj":
[[MyClassBank sharedBank] doneWithItem:obj];
Currently, My code would work if I where to use it this way, but I later realized that I sometimes add "obj" to an "NSCollection", and sometimes I call:
[theCollection removeAllObjects];
At first I thought about making my own class that is composed of a collection, then I would iterate the objects within the collection and call:
[[MyClassBank sharedBank] doneWithItem:obj];
But, that's too much of a hassle, isn't?
A neat idea (I think) popped into my mind, which is to override: -(oneway void)release;, so, I immediately jumped to Apple's documentation, but got stuck with the following:
You would only implement this method to define your own reference-counting scheme. Such implementations should not invoke the inherited method; that is, they should not include a release message to super.
Ao, I was reluctant to do that idea .. basically:
-(oneway void)release{
if ([self retainCount] == 1) {
//This will increment retain count by adding self to the collection.
[[MyClassBank sharedBank] doneWithItem:self];
}
[super release];
}
Is it safe to do that?
PS: Sorry for the long post, I want the whole idea to be clear..
EDIT:
How about overriding alloc alltogther and adding [[MyClassBank sharedBank] getReusableItem]; there?
Suggested method:
You're playing with the reference counting system. 99.9999999999999999% of the time this is a bad idea. I would highly recommend going with a different mechanism. Perhaps these objects could implement their own reference count that's independent of the retainCount? Then you could use that referenceCount to actually control when an object is ready to be re-used or not.
Not suggested method:
If, for some weird reason, you can't do that, then you could do the following thing that is still a bad idea and that i don't recommend you actually use:
You can override dealloc:
- (void)dealloc {
[ivar release], ivar = nil;
[anotherIvar release], anotherIvar = nil;
somePrimitive = 0;
// do not call [super dealloc]
}
- (void)_reallyDealloc {
[self dealloc]; // clean up any ivars declared at this level
[super dealloc]; // then continue on up the chain
}
Basically, the dealloc method would be the point at which the object is ready for re-use. When you're totally done with the object and finally want it to go away, you can use the _reallyDealloc method to continue on up the chain, eventually resulting in the object getting freed.
PLEASE don't do this. With things like Automatic Reference Counting, this is going to introduce you into a world of hurt and really bizarre debugging scenarios. A lot of the tools and classes and stuff depend on the reference counting mechanism to be working without alteration, so screwing around with it is usually not a Good Idea™.
For ppl who find this approach interesting/useful, Here is a cleaner way than calling [super dealloc]; directly (which is definitely bad)
//BAD!
//-(void)dealloc{
// for some reason, the retainCount at this point == 1
// if (![[BankStep sharedBank] purgeFlag]) {
// [self resetObject];
// [[BankStep sharedBank] doneWithItem:self];
// } else {
// [children release];
// [super dealloc];
// }
//}
by calling [[Bank sharedBank] purgeBank]; , set the flag to true, then remove all objects from the NSSet.
Adapted solution:
#Joe Osborn idea of using categories to implement a returnToBank Method!

Do we really need a safe release macro?

Quite a lot of people seem to use a macro such as
#define SAFE_RELEASE(X) [X release]; X = nil;
(myself included).
I've been reassessing why I am using it and wanted to canvas some opinion.
The purpose (I think) for using this macro is so that if you were to accidentally use your object after releasing it then you won't get a bad access exception because objective-c will quite happily ignore it when the object is nil.
It strikes me that this has the potential to mask some obscure bugs. Maybe it would actually be preferable for the program to crash when you try to use X again. That way during testing you can find the issue and improve the code.
Does this macro encourage lazy programming?
Thoughts?
I think you discuss all the pros and cons in your question, so I don't have a huge amount to add. Personally I don't use the construct. As you suggest, it can be used to paper over areas where people don't understand the memory management correctly. My preference is to fix the bug and not the symptom.
However, one compromise that I have seen from time to time is:
Make it crash during development
Do the var = nil; in production code
That way it might be more reliable with paying customers and still crashes early during development.
I'm not keen on this either, as you're using different code to your users and just because the buggy version keeps running doesn't mean it's doing the right thing. Not crashing but corrupting your database is not desirable behaviour...
I think it, or an equivalent such as self.myVar = nil where applicable, is a good. There are many cases where you simply can't just assign nil and assume any later access is a bug.
For example in UIKit it's good behavior to free up as many resources as possible when the OS ask. E.g.
- (void)didReceiveMemoryWarning
{
[myCachedData release];
[super didReceiveMemoryWarning];
}
Now, when my class is next used how am I to know that myCachedData is now invalid? The only way (short of having ANOTHER variable acting as a flag) is to set myCachedData to nil after releasing it. And condensing those two tedious lines into one is exactly what SAFE_RELEASE is for.
You don't need it, but it is handy to have. I use something similar in my apps. You can consider it "lazy", but when you have somewhere around 20 objects, writing these out manually gets tedious.
I was looking into the same question. With the bit of reading I did I just have something like this:
#define DEBUGGING
//#define PRODUCTION
#ifdef DEBUGGING
#define SAFE_RELEASE(X) [X release];
#else
#define SAFE_RELEASE(X) [X release]; X = nil;
#endif
So that way if I'm developing, I get the Crashes. In Production I don't.
Scott<-
As Andrew pointed out, there are cases where assigning nil isn't only avoiding bugs, but necessary. Just consider typical UIViewController code
- (void)viewDidLoad {
button = [UIButton buttonWithType:UIButtonTypeRoundedRect]; // autoreleased
[button retain]; // keep alive
}
- (void)viewDidUnload { // view has been removed
[button release];
}
- (void)dealloc { // destroying the view controller
[button release]; // <-- problem
}
In case the controller is loaded, later unloaded (because another view controller is displayed a memory is running low) and finally destroyed, the [button release] in dealloc would over-release the button (send a message to a released object). Therefore it it's necessary to assign nil. The safe solution would be:
- (void)viewDidUnload { // view has been removed
[button release];
button = nil;
}
- (void)dealloc { // destroying the view controller
[button release]; // <-- safe
}
For those cases a macro is nice and useful. To be more explicit about what it does, better name it RELEASE_AND_NIL
#define RELEASE_AND_NIL(X) [X release]; X = nil;

Composite NSOperation. Is this a bad idea?

For an iOS4.X application I am working on, we often need to perform an HTTP request, then parse the results, and do something with the results, and so on.
For this I created an NSOperation class to allow for composition of NSOperations using an NSOperation queue. Is there any issue with using NSOperationQueues for small things like this. Some have told me that the queues should be a more permanent thing.
I don't expect the nesting to be more than 2 levels deep in our application.
Here's an example of such usage:
#implementation CompositeOperation
- (id)initWithOperations:(NSArray *)operations {
if ((self = [super init])) {
operations_ = [operations retain];
[[operations_ lastObject] addObserver:self forKeyPath:#"isFinished" options:NSKeyValueObservingOptionNew context:nil];
}
return self;
}
-(void)dealloc {
[operations_ release];
[operationQueue_ release];
[super dealloc];
}
- (BOOL)isConcurrent {
return YES;
}
#synthesize isExecuting = isExecuting_;
#synthesize isFinished = isFinished_;
#synthesize operations = operations_;
- (void) start {
if (![self isCancelled]) {
operationQueue_ = [[NSOperationQueue alloc] init];
// TODO: Add code to execute this serially
[operationQueue_ addOperations:operations_ waitUntilFinished:NO];
}
}
- (void)cancel {
if (operationQueue_) {
[operationQueue_ cancelAllOperations];
}
[super cancel];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:#"isFinished"] && object == [operations_ lastObject]) {
[self setIsFinished:YES];
}
}
#end
Thanks,
Mike
I am the one who thinks it is a very good idea so that I even created library after it: CompositeOperations.
There are two operations: simple operation represented by COSimpleOperation object and composite operation represented by COCompositeOperation object.
Simple operation is a smallest possible unit - to quote documentation:
In a nutshell COSimpleOperation is a NSOperation with a small bit of convenience sugar on top of it. As an operational unit for composite operations it usually corresponds to one networking request or some small focused piece of work.
Composite operation is an operation which consists of sub-operations. To quote #mikelikespie:
The point of this object is to make it so one can represent multiple operations that are logically grouped as one operation.
...which is pretty much another description of Composite Design Pattern from Gang of Four Design Patterns.
Composite operation can be parallel or sequential.
Parallel operations are created just as in the code example in question:
NSArray *operations = #[
operation1, operation2, operation3
]; // each operation is NSOperation <COOperation> *
COCompositeOperation *parallelOperation = [[COCompositeOperation alloc] initWithOperations:operations];
To create sequential operation one should instantiate COCompositeOperation with an object conforming to COSequence protocol:
Sequential composition implies sequential flow: sub-operations are executed serially one after another. Sequencing is achieved via collaboration between COCompositeOperation and arbitrary class conforming to COSequence protocol which is used by composite operation as a delegate who decides what operations are and in which order to run them.
To make this composition of operations possible I needed to put small restriction on operations library works with: aside from being NSOperations both COSimpleOperation and COCompositeOperation also conform to <COOperation> protocol:
This conformance basically means that both operations when finished have 3 possible states:
a non-empty result field indicates success
a non-empty error field indicates failure
both empty result and error fields indicate that operation was cancelled from outside (using -[NSOperation cancel] method).
Operation can never have both result and error fields non-empty!
This convention allows Composite Operations to decide at a certain point whether to continue execution of particular group of operations or to stop it. For operations without a specific result [NSNull null] should be passed as result.
For me the rational behind this library was "just" to be able to represent operations so "that they are logically grouped as one operation". There are libraries that achieve the same kind of a higher-level functionality but at the same time they introduce concepts like: Signals in ReactiveCocoa or Promises like in PromiseKit which I don't really need or I would say do not agree with. I wanted something as simple as possible and based on good old well-known NSOperation/NSOperationQueue infrastructure so that's the point of the whole effort.
P.S. I hope this kind of answer fits the SO at least it corresponds exactly to what #mikelikespie was asking about 4 years ago.