I'm trying to make a subclass of NSCalendar, but without much luck. I've tried two ways:
thorough categories. I can create a modified object and a test method that I added (not part of NSCalendar) works just fine, but overriden methods don't work - e.g. if I call dateFromComponents:, the NSCalendar method is apparently called, not what I wrote in the category definition
regular subclass. In this case I can't even create an instance: initWithCalendarIdentifier throws a _CFRequireConcreteImplementation exception. Initially I only had a couple of methods overriden in the subclass, but then I've overriden all of the (documented) NSCalendar methods - and the result is the same.
Is it even possible to subclass NSCalendar?
The reason I want to do it is to make repeating Local Notifications with non-standard repeat intervals. The default functionality allows Local Notifications to repeat every [calendar unit], but I need irregular intervals - e.g. I can emulate "every 15 minutes" notifications by creating 4 "every hour" notifications 15 minutes apart, but I need them to fire at, say T+20, T+22, T+24, T+44, T+46, T+66 minutes and so on (T is the start time) - the interval between notifications is 20 minutes, then 2 minutes, then 20 minutes again and so on.
I was hoping that, since UILocalNotification wants an NSCalendar (in repeatCalendar property) to calculate when to fire the next notification, I can achieve what I want by overriding, say, dateFromComponents to just return [NSDate dateWithIntervalSinceNow] with interval alternating between 20 and 2 minutes - but my cunning plan seems to have a major problem because of the inability to subclass NSCalendar.
Edit: This whole thing is needed for when the app is in the background. In the foreground I use timers, just like No one in particular suggests.
Even if you do manage to subclass NSCalendar, I doubt it'll work. I strongly suspect that local notifications are scheduled by SpringBoard, and I don't think it's going to launch/resume your app every time it needs to see what the next fire date is.
The first step is to find out what UILocalNotification is doing with your calendar. The easiest way to do this is to write an NSObject subclass which forwards undefined method calls and prints log messages (respondsToSelector:, methodSignatureForSelector:, forwardInvocation:). Generally, you want something like if ([super respondsToSelector:selector]) { return [super ...]; } else { return [target ...]; }.
Then, the easiest hack is to write a class which implements the necessary methods of NSCalendar for your purposes.
You might also consider calling [super init]; -[NSCalendar initWithCalendarIdentifier:] is likely to return a different self (e.g. [self release]; return [[NSGregorianCalendar alloc] init]), and you don't want that. What calendar identifier are you passing it? Maybe it's complaining that it requires a "concrete implementation" that it knows about for the calendar identifier you're passing.
A direct inherit from NSCalendar is tricky because I think that it's a class cluster. I'm a bit fuzzy on this concept so I'll give you a link to the Apple document instead of making a greater fool of myself.
http://developer.apple.com/Mac/library/documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/CocoaObjects.html#//apple_ref/doc/uid/TP40002974-CH4-SW34
Try using the NSTimer method
+ (NSTimer *)scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:
Set the repeats to TRUE and have a time interval of 2 minutes. Have a counter that you set to 1 or 10. Everytime the selector is called you decrement the counter until it reaches 0 when you do your work and reset the counter.
Related
I need to do some testing that involves moving the "phone" backwards and forwards through several days. I'd like to do this on the simulator. Is there any available hack that allows the date as seen on the simulator to be changed, without having to change the Mac date?
Looks like it's pretty tough... How about using xcodebuild to automate building and running the app from a script and using systemsetup -setdate <mm:dd.yy> to change date in between different runs? Then you wouldn't need to change anything in code.
You can use method swizzling to replace the implementation of [NSDate date] at runtime to return a value of your choosing.
For more info on method swizzling, see http://www.icodeblog.com/2012/08/08/using-method-swizzling-to-help-with-test-driven-development/.
I needed to test my app automatically, which required changing the sys time. I did, what Tom suggested: happy hacky method swizzling.
For demonstrative purposes, I only change [NSDate date] but not [NSDate dateWithTimeIntervalSince1970:].
First your need to create your class method that serves as the new [NSDate date]. I implemented it to simply shift the time by a constant timeDifference.
int timeDifference = 60*60*24; //shift by one day
NSDate* (* original)(Class,SEL) = nil;
+(NSDate*)date{
NSDate* date = original([NSDate class], #selector(date));
return [date dateByAddingTimeInterval:timeDifference];
}
So far, pretty easy. Now comes the fun part.
We get the methods from both classes and exchange implementation (it worked for me in the AppDelegate, but not in my UITests class). For this you will need to import objc/runtime.h.
Method originalMethod = class_getClassMethod([NSDate class], #selector(date));
Method newMethod = class_getClassMethod([self class], #selector(date));
//save the implementation of NSDate to use it later
original = (NSDate* (*)(Class,SEL)) [NSDate methodForSelector:#selector(date)];
//happy swapping
method_exchangeImplementations(originalMethod, newMethod);
Obviously, make sure that you use non of this in your deployed application.
Lastly, I can only agree with the answers before that it is quite questionable why Apple didn't add native support for this.
If you are creating an app, just change the date in the app for testing and you can remove it when you publish it.
I am using an NSTimer that runs down from 15 seconds in a multiple choice quiz app. The app has two possible outcomes. The time may run down to zero, and the incorrectAnswer view is shown, in which case the Timer is invalidated/stopped and the static integer for its time is reset back to 15 for the next question.
However, the other possible outcome is that an answer is selected before time runs down, in which case I use the method viewWillDisappear to trigger further action. My problem is that I cannot reset the static integer for time from this method, because it is declared in the method above. I tried declaring it in the .h file, but there are problems because the integer is static.
I want to know if there is a boolean expression that evaluates if the current view has disappeared, because this way I can keep everything in the same method and be able to reset the static integer for time.
First, if your timer variable local to the class, it doesn't have to be declared as static. Secondly, you have two opportunities to address your problem from the viewController: viewWillDisappear and viewDidDisappear. Lastly, if you need to know if a view property has changed, you can do it via a KVO method. The problem you'll run into is if the view has truly disappeared, the view object may be toast by the time you reference it. Without more info, there is no way to tell what problem you're truly having.
Also, once you invalidate a timer, you can no longer use it. You must create a new timer.
Sorry if this is a noob question, but I get tripped up on some simple things as I'm starting to learn to program. If I use a NSDateFormatter in one of my ViewControllers to display the date I want in a certain format, and the format doesn't change, is it "best practices" to declare that NSDateFormatter as an ivar of my class or property of my class and initialize it in the viewDidLoad so I can reuse it in my different methods? Right now I just instantiate one whenever I need it in a method that deals with the display and was wondering if it's better to just keep declaring it, or declare it once and just use it throughout the viewController class. thanks!
It's not a "noob question"; it's a reasonable question with a reasonable answer.
From a pure efficiency standpoint, you're optimizing prematurely. Don't worry, be happy. If you're managing memory correctly (so that you're not leaking NSDateFormatters) it really shouldn't matter how you obtain a particular instance, especially given that this is such a lightweight object. If you're creating a new NSDateFormatter 1000 times in a loop, you're being silly, but if you're creating the object now and then when you need it and it's going back out of existence properly, it's no big deal.
On the other hand, from an architectural standpoint, make sure what you are doing is DRY. If the date formatter needs any configuration at all, don't repeat yourself each time you create it; write a method that supplies the date formatter the same way each time so that the configuration code is all in just one place.
Instantiating new objects always comes at the price of memory and computing time, so if it's possible without much effort you should try to declare it once and then reuse it, at least within the same class. NSDateFormatter is not thread-safe, though, so you can't simply share one instance between different threads.
For any object, best practice is to just declare it at run time, use it and release it, so that the time taken by that object in memory remains maximum.
We make an ivar when we need the value of that ivar same throughout the class, like any age for an employee, it will be checked in different methods as in seniority, in ageWise category etc. And further if this iVar is an object, then in iPhone, it is a good practice always to be use it as property, so that the memory management problem shifts towards the compiler end.
Now in your case, you may generate a simple method that will take the date object and return the string, or any String as parameter and return date object, make an NSDateFormater there and use it. No need to make it as iVar.
I have many methods that need the previous one to complete before firing the next one. I'm thinking I should NSNotificationCenter rather than performSelector afterDelay and just hope the method is done by that time.
Can someone map out how and where to add the notification to Method1, Method2 and Method3 where 1 needs to complete (not just fire) before 2 before 3.
Thanks
In general do not use notifications as method calls. They should be used to indicate that something did or will occur.
From Apple's "Coding Guidelines for Cocoa":
Notifications are identified by global NSString objects whose names are composed in this way:
[Name of associated class] + [Did | Will] + [UniquePartOfName] + Notification
For example:
NSApplicationDidBecomeActiveNotification
NSWindowDidMiniaturizeNotification
NSTextViewDidChangeSelectionNotification
NSColorPanelColorDidChangeNotification
I'm about to create a function which adds two NSDateComponents together is there any advantage to putting this in a C style function or should it go in a Obj-C method?
Is there ever a reason to use one rather then the other or should I always stick to Obj-C?
BTW: Not that it makes any difference I'm sure but this is for an app on the iPhone
Many thanks
In Objective-C, the proper terminology is not to “call a method on” an object, but to “send a message to” an object.
That makes the decision easy: Are you sending a message to an object? Are you telling it to do something or asking it for information? If so, then make the object respond to that message by putting the code in a method. If not (if the task is independent of any object), then make it a function.
You might browse the Foundation functions, UIKit functions, and AppKit functions lists for examples of the sort of object-independence that makes something belong in a function rather than a method.
I'm about to create a function which adds to NSDateComponents together is there any advantage to putting this in a C style function or should it go in a Obj-C method?
I would put that into an instance method categoried onto NSDateComponents. The call (message) would look like [componentsA componentsByAddingComponents_PRH:componentsB]. (Note that I included my initials so that if Apple ever adds a componentsByAddingComponents: method of their own, my app's behavior won't suddenly change when users upgrade their devices to the new OS.)
One existing example of this is NSDecimalNumber's decimalNumberByAdding: method.
Function calls have slightly less overhead than Objective C method calls, but that's not a good reason to use them unless you have already detected a critical performance problem in exactly that area.
Objective C programs look very different from plain C programs. Maintaining consistency in the look and the idiom of the language is a good enough reason to implement almost all simple behaviours as methods rather than as C functions.
Take a look at where Cocoa-Touch uses functions rather than methods for an example of this approach.
More likely you'll want to use an Objective-C method implemented as a category on NSDateComponents.
#interface NSDateComponents (DGCalculations)
/*!
\brief Add date components
\details Add the given date components to the receiver and
return the result as a new date components object.
*/
- (NSDateComponents *)componentsByAddingComponents:(NSDateComponents *)components;
#end
#implementation NSDateComponents (DGCalculations)
- (NSDateComponents *)componentsByAddingComponents:(NSDateComponents *)components {
NSDateComponents *result = [[[NSDateComponents alloc] init] autorelease];
[result setDay:[self day] + [components day]];
// handle the rest
return result;
}
#end
The use then turns out to be a little nicer:
result = [firstComponents add:secondComponents];
I'm not clear on what you mean by "adds to NSDateComponents together". Could you explain exactly what you need to do?
Whether to make it a function or a method is largely a question of how you expect to use it. Is there some particular object that needs to do this, or is the need likely to show up in many places in your program?