How do I use an NSTimer
? Can anyone give me step by step instructions?
Objective-c – How to use NSTimer
cocoanstimerobjective c
Related Solutions
An Objective-C delegate is an object that has been assigned to the delegate
property another object. To create one, you define a class that implements the delegate methods you're interested in, and mark that class as implementing the delegate protocol.
For example, suppose you have a UIWebView
. If you'd like to implement its delegate's webViewDidStartLoad:
method, you could create a class like this:
@interface MyClass<UIWebViewDelegate>
// ...
@end
@implementation MyClass
- (void)webViewDidStartLoad:(UIWebView *)webView {
// ...
}
@end
Then you could create an instance of MyClass and assign it as the web view's delegate:
MyClass *instanceOfMyClass = [[MyClass alloc] init];
myWebView.delegate = instanceOfMyClass;
On the UIWebView
side, it probably has code similar to this to see if the delegate responds to the webViewDidStartLoad:
message using respondsToSelector:
and send it if appropriate.
if([self.delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
[self.delegate webViewDidStartLoad:self];
}
The delegate property itself is typically declared weak
(in ARC) or assign
(pre-ARC) to avoid retain loops, since the delegate of an object often holds a strong reference to that object. (For example, a view controller is often the delegate of a view it contains.)
Making Delegates for Your Classes
To define your own delegates, you'll have to declare their methods somewhere, as discussed in the Apple Docs on protocols. You usually declare a formal protocol. The declaration, paraphrased from UIWebView.h, would look like this:
@protocol UIWebViewDelegate <NSObject>
@optional
- (void)webViewDidStartLoad:(UIWebView *)webView;
// ... other methods here
@end
This is analogous to an interface or abstract base class, as it creates a special type for your delegate, UIWebViewDelegate
in this case. Delegate implementors would have to adopt this protocol:
@interface MyClass <UIWebViewDelegate>
// ...
@end
And then implement the methods in the protocol. For methods declared in the protocol as @optional
(like most delegate methods), you need to check with -respondsToSelector:
before calling a particular method on it.
Naming
Delegate methods are typically named starting with the delegating class name, and take the delegating object as the first parameter. They also often use a will-, should-, or did- form. So, webViewDidStartLoad:
(first parameter is the web view) rather than loadStarted
(taking no parameters) for example.
Speed Optimizations
Instead of checking whether a delegate responds to a selector every time we want to message it, you can cache that information when delegates are set. One very clean way to do this is to use a bitfield, as follows:
@protocol SomethingDelegate <NSObject>
@optional
- (void)something:(id)something didFinishLoadingItem:(id)item;
- (void)something:(id)something didFailWithError:(NSError *)error;
@end
@interface Something : NSObject
@property (nonatomic, weak) id <SomethingDelegate> delegate;
@end
@implementation Something {
struct {
unsigned int didFinishLoadingItem:1;
unsigned int didFailWithError:1;
} delegateRespondsTo;
}
@synthesize delegate;
- (void)setDelegate:(id <SomethingDelegate>)aDelegate {
if (delegate != aDelegate) {
delegate = aDelegate;
delegateRespondsTo.didFinishLoadingItem = [delegate respondsToSelector:@selector(something:didFinishLoadingItem:)];
delegateRespondsTo.didFailWithError = [delegate respondsToSelector:@selector(something:didFailWithError:)];
}
}
@end
Then, in the body, we can check that our delegate handles messages by accessing our delegateRespondsTo
struct, rather than by sending -respondsToSelector:
over and over again.
Informal Delegates
Before protocols existed, it was common to use a category on NSObject
to declare the methods a delegate could implement. For example, CALayer
still does this:
@interface NSObject(CALayerDelegate)
- (void)displayLayer:(CALayer *)layer;
// ... other methods here
@end
This tells the compiler that any object might implement displayLayer:
.
You would then use the same -respondsToSelector:
approach as described above to call this method. Delegates implement this method and assign the delegate
property, and that's it (there's no declaring you conform to a protocol). This method is common in Apple's libraries, but new code should use the more modern protocol approach above, since this approach pollutes NSObject
(which makes autocomplete less useful) and makes it hard for the compiler to warn you about typos and similar errors.
Compare method
Either you implement a compare-method for your object:
- (NSComparisonResult)compare:(Person *)otherObject {
return [self.birthDate compare:otherObject.birthDate];
}
NSArray *sortedArray = [drinkDetails sortedArrayUsingSelector:@selector(compare:)];
NSSortDescriptor (better)
or usually even better:
NSSortDescriptor *sortDescriptor;
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"birthDate"
ascending:YES];
NSArray *sortedArray = [drinkDetails sortedArrayUsingDescriptors:@[sortDescriptor]];
You can easily sort by multiple keys by adding more than one to the array. Using custom comparator-methods is possible as well. Have a look at the documentation.
Blocks (shiny!)
There's also the possibility of sorting with a block since Mac OS X 10.6 and iOS 4:
NSArray *sortedArray;
sortedArray = [drinkDetails sortedArrayUsingComparator:^NSComparisonResult(Person *a, Person *b) {
return [a.birthDate compare:b.birthDate];
}];
Performance
The -compare:
and block-based methods will be quite a bit faster, in general, than using NSSortDescriptor
as the latter relies on KVC. The primary advantage of the NSSortDescriptor
method is that it provides a way to define your sort order using data, rather than code, which makes it easy to e.g. set things up so users can sort an NSTableView
by clicking on the header row.
Related Topic
- Ios – How to check for an active Internet connection on iOS or macOS
- Ios – How to check if a string contains another string in Objective-C
- Ios – Xcode – How to fix ‘NSUnknownKeyException’, reason: … this class is not key value coding-compliant for the key X” error
- Ios – How to check iOS version
- Ios – Passing data between view controllers
- Ios – performSelector may cause a leak because its selector is unknown
- Objective-c – How to create a NSTimer on a background thread
- Swift – How to call Objective-C code from Swift
Best Answer
Firstly I'd like to draw your attention to the Cocoa/CF documentation (which is always a great first port of call). The Apple docs have a section at the top of each reference article called "Companion Guides", which lists guides for the topic being documented (if any exist). For example, with
NSTimer
, the documentation lists two companion guides:For your situation, the Timer Programming Topics article is likely to be the most useful, whilst threading topics are related but not the most directly related to the class being documented. If you take a look at the Timer Programming Topics article, it's divided into two parts:
For articles that take this format, there is often an overview of the class and what it's used for, and then some sample code on how to use it, in this case in the "Using Timers" section. There are sections on "Creating and Scheduling a Timer", "Stopping a Timer" and "Memory Management". From the article, creating a scheduled, non-repeating timer can be done something like this:
This will create a timer that is fired after 2.0 seconds and calls
targetMethod:
onself
with one argument, which is a pointer to theNSTimer
instance.If you then want to look in more detail at the method you can refer back to the docs for more information, but there is explanation around the code too.
If you want to stop a timer that is one which repeats, (or stop a non-repeating timer before it fires) then you need to keep a pointer to the
NSTimer
instance that was created; often this will need to be an instance variable so that you can refer to it in another method. You can then callinvalidate
on theNSTimer
instance:It's also good practice to
nil
out the instance variable (for example if your method that invalidates the timer is called more than once and the instance variable hasn't been set tonil
and theNSTimer
instance has been deallocated, it will throw an exception).Note also the point on Memory Management at the bottom of the article: