I have 3 separate ibeacons placed in 3 different rooms. When entering the region of the beacon the didRangeBeacon method runs every second, Thus resulting in an infinite number of notifications when in range.
This is the code i have:
BOOL _isInsideRegion;
- (void)locationManager:(CLLocationManager*)manager didRangeBeacons:(NSArray*)beacons inRegion:(CLBeaconRegion*)region {
CLBeacon *firstBeacon = [beacons firstObject];
int major = [firstBeacon.major intValue];
int minor = [firstBeacon.minor intValue];
if (major == 43005 && minor == 52679) {
if (!_isInsideRegion) {
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.soundName = #"Default";
notification.alertBody = #"Green";
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
self.beaconColour.text = #"Green";
self.minor.text = [NSString stringWithFormat:#"%D", minor];
self.major.text = [NSString stringWithFormat:#"%D", major];
}
}
else if (major == 48891 && minor == 47852) {
if (!_isInsideRegion) {
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.soundName = #"Default";
notification.alertBody = #"blue";
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
self.beaconColour.text = #"Blue";
self.minor.text = [NSString stringWithFormat:#"%D", minor];
self.major.text = [NSString stringWithFormat:#"%D", major];
}
}
else if (major == 59510 && minor == 42953) {
if (!_isInsideRegion) {
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.soundName = #"Default";
notification.alertBody = #"dark blue";
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
self.beaconColour.text = #"Dark Blue";
self.minor.text = [NSString stringWithFormat:#"%D", minor];
self.major.text = [NSString stringWithFormat:#"%D", major];
}
}
}
Can anybody help me so that it gives one notification upon entry, and that when i then walk to the next beacon i get another notification specific to that beacon.
Thanks.
Use the locationManager:didEnterRegion: method.
This method is called when the user enters a beacon region defined by your app.
- (void)locationManager:(CLLocationManager *)manager
didEnterRegion:(CLBeaconRegion *)region {
NSLog(#"Did Enter Region for %#", region.identifier);
//Show Notification
}
Related
I have an app that shows twitter account feed. So I have ImageView, textLabel and detailLabel for the content of the feed. The problem is that when all the data is loaded, the uiimage doesn't appear. When I click on the cell or scroll up-down, images are set. here is some of my code.
-(void)getImageFromUrl:(NSString*)imageUrl asynchronouslyForImageView:(UIImageView*)imageView andKey:(NSString*)key{
dispatch_async(dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL *url = [NSURL URLWithString:imageUrl];
__block NSData *imageData;
dispatch_sync(dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
imageData =[NSData dataWithContentsOfURL:url];
if(imageData){
[self.imagesDictionary setObject:[UIImage imageWithData:imageData] forKey:key];
dispatch_sync(dispatch_get_main_queue(), ^{
imageView.image = self.imagesDictionary[key];
});
}
});
});
}
- (void)refreshTwitterHomeFeedWithCompletion {
// Request access to the Twitter accounts
ACAccountStore *accountStore = [[ACAccountStore alloc] init];
ACAccountType *accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
[accountStore requestAccessToAccountsWithType:accountType options:nil completion:^(BOOL granted, NSError *error){
if (granted) {
NSArray *accounts = [accountStore accountsWithAccountType:accountType];
// Check if the users has setup at least one Twitter account
if (accounts.count > 0)
{
ACAccount *twitterAccount = [accounts objectAtIndex:0];
NSLog(#"request.account ...%#",twitterAccount.username);
NSURL* url = [NSURL URLWithString:#"https://api.twitter.com/1.1/statuses/home_timeline.json"];
NSDictionary* params = #{#"count" : #"50", #"screen_name" : twitterAccount.username};
SLRequest *request = [SLRequest requestForServiceType:SLServiceTypeTwitter
requestMethod:SLRequestMethodGET
URL:url parameters:params];
request.account = twitterAccount;
[request performRequestWithHandler:^(NSData *responseData,
NSHTTPURLResponse *urlResponse, NSError *error) {
if (error)
{
NSString* errorMessage = [NSString stringWithFormat:#"There was an error reading your Twitter feed. %#",
[error localizedDescription]];
NSLog(#"%#",errorMessage);
}
else
{
NSError *jsonError;
NSArray *responseJSON = [NSJSONSerialization
JSONObjectWithData:responseData
options:NSJSONReadingAllowFragments
error:&jsonError];
if (jsonError)
{
NSString* errorMessage = [NSString stringWithFormat:#"There was an error reading your Twitter feed. %#",
[jsonError localizedDescription]];
NSLog(#"%#",errorMessage);
}
else
{
NSLog(#"Home responseJSON..%#",(NSDictionary*)responseJSON.description);
dispatch_async(dispatch_get_main_queue(), ^{
[self reloadData:responseJSON];
});
}
}
}];
}
}
}];
}
-(void)reloadData:(NSArray*)jsonResponse
{
self.tweets = jsonResponse;
[self.tableView reloadData];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return self.tweets.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
SNTwitterCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(!cell)
{
cell = [[SNTwitterCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
NSDictionary *tweetDictionary = self.tweets[indexPath.row];
NSDictionary *user = tweetDictionary[#"user"];
NSString *userName = user[#"name"];
NSString *tweetContaint = tweetDictionary[#"text"];
NSString* imageUrl = [user objectForKey:#"profile_image_url"];
[self getImageFromUrl:imageUrl asynchronouslyForImageView:cell.imageView andKey:userName];
cell.profileImage.image = [UIImage imageNamed:#"images.png"];
NSArray *days = [NSArray arrayWithObjects:#"Mon ", #"Tue ", #"Wed ", #"Thu ", #"Fri ", #"Sat ", #"Sun ", nil];
NSArray *calendarMonths = [NSArray arrayWithObjects:#"Jan", #"Feb", #"Mar",#"Apr", #"May", #"Jun", #"Jul", #"Aug", #"Sep", #"Oct", #"Nov", #"Dec", nil];
NSString *dateStr = [tweetDictionary objectForKey:#"created_at"];
for (NSString *day in days) {
if ([dateStr rangeOfString:day].location == 0) {
dateStr = [dateStr stringByReplacingOccurrencesOfString:day withString:#""];
break;
}
}
NSArray *dateArray = [dateStr componentsSeparatedByString:#" "];
NSArray *hourArray = [[dateArray objectAtIndex:2] componentsSeparatedByString:#":"];
NSDateComponents *components = [[NSDateComponents alloc] init];
NSString *aux = [dateArray objectAtIndex:0];
int month = 0;
for (NSString *m in calendarMonths) {
month++;
if ([m isEqualToString:aux]) {
break;
}
}
components.month = month;
components.day = [[dateArray objectAtIndex:1] intValue];
components.hour = [[hourArray objectAtIndex:0] intValue];
components.minute = [[hourArray objectAtIndex:1] intValue];
components.second = [[hourArray objectAtIndex:2] intValue];
components.year = [[dateArray objectAtIndex:4] intValue];
NSTimeZone *gmt = [NSTimeZone timeZoneForSecondsFromGMT:2];
[components setTimeZone:gmt];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
[calendar setTimeZone:[NSTimeZone systemTimeZone]];
NSDate *date = [calendar dateFromComponents:components];
NSString *tweetDate = [self getTimeAsString:date];
NSString *tweetValues = [NSString stringWithFormat:#"%# :%#",userName,tweetDate];
cell.textLabel.text = [NSString stringWithFormat:#"%#",tweetValues];
cell.detailTextLabel.text = [NSString stringWithFormat:#"%#",tweetContaint];
[cell.detailTextLabel setFont:[UIFont fontWithName:#"Helvetica" size:20]];
return cell;
}
- (NSString*)getTimeAsString:(NSDate *)lastDate {
NSTimeInterval dateDiff = [[NSDate date] timeIntervalSinceDate:lastDate];
int nrSeconds = dateDiff;//components.second;
int nrMinutes = nrSeconds / 60;
int nrHours = nrSeconds / 3600;
int nrDays = dateDiff / 86400; //components.day;
NSString *time;
if (nrDays > 5){
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateStyle:NSDateFormatterShortStyle];
[dateFormat setTimeStyle:NSDateFormatterNoStyle];
time = [NSString stringWithFormat:#"%#", [dateFormat stringFromDate:lastDate]];
} else {
// days=1-5
if (nrDays > 0) {
if (nrDays == 1) {
time = #"1 day ago";
} else {
time = [NSString stringWithFormat:#"%d days ago", nrDays];
}
} else {
if (nrHours == 0) {
if (nrMinutes < 2) {
time = #"just now";
} else {
time = [NSString stringWithFormat:#"%d minutes ago", nrMinutes];
}
} else { // days=0 hours!=0
if (nrHours == 1) {
time = #"1 hour ago";
} else {
time = [NSString stringWithFormat:#"%d hours ago", nrHours];
}
}
}
}
return [NSString stringWithFormat:NSLocalizedString(#"%#", #"label"), time];
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 100;
}
The fundamental problem is that the standard imageView property of the standard table view cell will automatically resize itself based upon the image that is present when cellForRowAtIndexPath finishes. But since there is no image yet when you first present the table, the cell is laid out as if there's no image. And when you asynchronously update the image view's image, it won't resize the image view.
There are a couple of ways of solving this:
Don't use the default imageView provided by UITableViewCell, but rather define your own custom cell subclass with an IBOutlet to its own UIImageView property. Make sure that this UIImageView has a fixed layout (i.e., it doesn't use the intrinsic size derived from the underlying image).
If you do that, you can asynchronously update the image property for your custom UIImageView outlet, and because the layout was not contingent upon the presence of the image, any asynchronous updates of that image should appear correctly.
When you receive the image, don't just set the image view's image property, but rather reload the whole row associated with that NSIndexPath using reloadRowsAtIndexPaths.
If you do this, the cell will be laid out correctly assuming that you retrieve the image from the cache correctly, and do so before cellForRowAtIndexPath finishes.
Note, if you do this, you will need to fix your getImageFromUrl to actually try to retrieve the image from the cache first (and do this from the main queue, before to dispatch to the background queue), or else you'll end up in an endless loop.
Having said that, there are deeper problems here.
As I mentioned above, you're caching your images, but never using the cache when retrieving the images.
You are asynchronously updating the image view.
You should initialize the image property of the UIImageView before you initiate the new asynchronous fetch, otherwise when a cell is reused, you'll see the old image there until the new image is retrieved.
What if the cell was reused in the intervening period between calling getImageFromUrl and when the asynchronous request finishes? You'll be updating the image view for the wrong cell. (This problem will be more apparent when doing this over a slow connection. Run your code using the network link conditioner to simulate slow connections and you'll see the problem I'm describing.)
What if the user rapidly scrolls down to the 100th row in the table? The network requests for the visible cells will be backlogged behind the other 99 image requests. You could even get timeout errors on slow connections.
There are a bunch of tactical little issues in getImageFromUrl.
Why dispatching synchronously from global queue to another global queue? That's unnecessary. Why dispatching UI update synchronously to main thread? That's inefficient.
Why define imageData as __block outside of the block; just define it within the block and you don't need __block qualifier.
What if you didn't receive a valid UIImage from the network request (e.g. you got a 404 error message); the existing code would crash. There are all sorts of responses the server might provide which are not a valid image, and you really must identify that situation (i.e. make sure that not only was NSData you received not nil, but also that the UIImage that you created from it was not nil, too).
I'd probably use NSCache rather than NSMutableDictionary for the cache. Also, regardless of whether you use NSCache or NSMutableDictionary, you want to make sure that you respond to memory pressure events and empty that cache if needed.
We can go through all of these individual problems, but it's a non-trivial amount of work to fix all of this. I might therefore suggest you consider the UIImageView categories of SDWebImage or AFNetworking. They take care of most of these issues, plus others. It will make your life much, much easier.
I have added a local notification programmatically like below:
UILocalNotification *eventLocalNotification=[[UILocalNotification alloc]init];
eventLocalNotification.fireDate=myDate;
eventLocalNotification.timeZone=[NSTimeZone defaultTimeZone];
eventLocalNotification.alertBody=#"My notification";
eventLocalNotification.soundName=UILocalNotificationDefaultSoundName;
Can I change the firingDate, timeZone, alertBody, or any other property?
After searching a lot over internet, I got a thing that we can't edit a UILocal Notification once added. But sure there is another way that I have found.
Get all the Local notification of your device.
Search the respective local notification
Cancel that notification
Create a New one
Below is the method to add the notification.
-(void)setLocalNotification
{
UILocalNotification *eventLocalNotification = [[UILocalNotification alloc]init];
eventLocalNotification.fireDate = //set firing Date of NSDate type
eventLocalNotification.timeZone = [NSTimeZone defaultTimeZone];
eventLocalNotification.alertBody = [NSString stringWithFormat:#"An event has arrived\n Event Name: %#",notificationName.Text];
eventLocalNotification.soundName = UILocalNotificationDefaultSoundName;
if ([repeat isEqualToString:#"Once"]){
eventLocalNotification.repeatInterval = 0;
}else if ([repeat isEqualToString:#"Daily"]){
eventLocalNotification.repeatInterval = NSDayCalendarUnit;
}else if ([repeat isEqualToString:#"Weekly"]){
eventLocalNotification.repeatInterval = NSWeekCalendarUnit;
}else if ([repeat isEqualToString:#"Monthly"]){
eventLocalNotification.repeatInterval = NSMonthCalendarUnit;
}else if ([repeat isEqualToString:#"Yearly"]){
eventLocalNotification.repeatInterval = NSYearCalendarUnit;
}
NSDictionary *info = [NSDictionary dictionaryWithObject:[NSString stringWithFormat:#"%#",notificationName.text] forKey:#"name"];
eventLocalNotification.userInfo = info;
NSLog(#"notification userInfo gets name : %#",[info objectForKey:#"name"]);
[[UIApplication sharedApplication] scheduleLocalNotification:eventLocalNotification];
NSLog(#"Notification created");
}
Below is the function to cancel the notification
-(void)cancelLocalNotification
{
UILocalNotification * notificationToCancel=nil;
for(UILocalNotification * aNotif in [[UIApplication sharedApplication] scheduledLocalNotifications])
{
NSLog(#"%#",[aNotif.userInfo objectForKey:#"name"]);
if([[aNotif.userInfo objectForKey:#"name"] isEqualToString:notificationName ])
{
notificationToCancel = aNotif;
[[UIApplication sharedApplication] cancelLocalNotification:notificationToCancel];
NSLog(#"Notification Cancelled");
break;
}
}
}
Hope you will get benefit from it. Best of Luck
To set your date and time, you will have to use NSDateComponents and instantiate NSDate twice. One for current date and another will be your desirable date. Than set desirable NSDate's instance to fireDate of UILocalNotification's object.
eventLocalNotification.fireDate = desiredDate;
for timezone, keep it to default the way you did.
eventLocalNotification.timeZone = [NSTimeZone defaultTimeZone];
Alert body could be anything, just put your context.
eventLocalNotification.alertBody = #"DESIRED CONTEXT";
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 11 years ago.
I have been building a program for the past few months. I finally got to the point where everything was working great. The program has been built for iOS 5 from the beginning. And i just checked on things that i thought i had cemented in and that were working fine when i checked a few days ago. But now everything is acting goofy. My recorder stopped working. Not sure in what area. My seeker's values arnt changing as they should. Playback of the recording is not working. The recorder used to take a second to load up where it would freeze the screen then start, now it is instantaneous which i find odd. Im sorry if im being vague but im totally stumped. The record button sets off a timer after the record command. In the timer there is an if statement, which has many clauses, one being myRecorder.isRecording == NO, and yet the if statement acts as if the conditions are met and executes the code inside, despite the recorder being told to record right before the timer even started. I AM BAFFLED. Please help. Thanks
Code for record button:
- (IBAction)record:(id)sender {
//[myPlayer play];
if ([sender tag] == 2){
[self stop];
[sender setTag:1];
[sender setTitle:#"Record"];
[sender setEnabled:NO];
NSLog(#"Tag is 2");
}else{
if ([myPlayer isPlaying]){
[myPlayer pause];
[myPlayer setCurrentTime:0];
}
anotherControl = 0;
theToolbar.userInteractionEnabled = NO;
[theToolbar setTintColor:myColor];
[theToolbar setAlpha:.5];
[controlSong setTintColor:[UIColor blackColor]];
beatPackTable.userInteractionEnabled = NO;
beatPackTable.hidden = YES;
onScreenTut.text = #"(Hold phone to your face and begin. When finished recording, hit the stop button)";
recordCover.titleLabel.text = #"Recording";
recordCover.titleLabel.textAlignment = UITextAlignmentCenter;
recordCover.hidden = NO;
NSString *docsDir;
myDate = [[NSDate alloc] init];
myDate = [NSDate date];
seekerTwo.userInteractionEnabled = NO;
homeButton.enabled = NO;
tracksButton.enabled = NO;
tutButton.enabled = NO;
previewBeatTwo.enabled = NO;
previewPauseTwo.enabled = NO;
/*
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeStyle:NSDateFormatterShortStyle];
[dateFormatter setDateStyle:NSDateFormatterShortStyle];
NSString *myDate2 = [NSString stringWithFormat:#"%#",[dateFormatter stringFromDate:myDate]];
*/
// dirPaths = NSSearchPathForDirectoriesInDomains(
// NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = NSTemporaryDirectory();
NSString *soundFilePath = [docsDir
stringByAppendingPathComponent:[NSString stringWithFormat:#"%#%i.caf",myDate,control]];
NSURL *soundFileURL = [NSURL fileURLWithPath:soundFilePath];
NSDictionary *recordSettings = [NSDictionary
dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:AVAudioQualityLow],
AVEncoderAudioQualityKey,
[NSNumber numberWithInt:16],
AVEncoderBitRateKey,
[NSNumber numberWithInt: 2],
AVNumberOfChannelsKey,
[NSNumber numberWithFloat:44100.0],
AVSampleRateKey,
nil];
NSError *error = nil;
myNewRecorder = [[AVAudioRecorder alloc]
initWithURL:soundFileURL
settings:recordSettings
error:&error];
if (error)
{
NSLog(#"error: %#", [error localizedDescription]);
} else {
[myNewRecorder prepareToRecord];}
seeker.userInteractionEnabled = NO;
voiceVolumeControl.enabled =YES;
recordButton.enabled = NO;
stopButton.enabled = YES;
myPlayer.currentTime = 0;
[myNewRecorder record];
[myPlayer play];
[NSTimer scheduledTimerWithTimeInterval:1.0f
target:self
selector:#selector(updateCounter:)
userInfo:nil
repeats:YES];
if ([sender tag] == 1){
[sender setTitle:#"End"];
[sender setTag:2];
}}
NSLog(#"%#",myDate);
}
Code for timer:
-(void)updateCounter:(NSTimer *)theTimer{
if ([myNewRecorder isRecording]) {
[seeker setValue:myPlayer.currentTime/myPlayer.duration animated:YES];}
if ([myPlayer2 isPlaying])
{
[seeker setValue:myPlayer2.currentTime/myPlayer2.duration animated:YES];
}
if ([myPlayer isPlaying] && myPlayer2.isPlaying == NO && myNewRecorder.isRecording == NO && isNotepadOpen == NO && anotherControl == 0) {
[myPlayer stop];
myPlayer.currentTime = 0;
[seeker setValue:0];
playButton.enabled = YES;
stopButton.enabled = NO;
NSLog(#"Its the timer for some reason");
}
if ([myNewRecorder isRecording] || [myPlayer isPlaying] || [myPlayer2 isPlaying]){
[[UIApplication sharedApplication] setIdleTimerDisabled:YES];
}else{
[[UIApplication sharedApplication] setIdleTimerDisabled:NO];
}
if ([myPlayer isPlaying]){
[seekerTwo setValue:myPlayer.currentTime/myPlayer.duration animated:YES];
}
}
See my answer (and others) to that question on Programmers SE: “It was working yesterday, I swear!” What can you do?
Basically, find what has changed since the sudden bugs, maybe a new delivery of iOS 5, Xcode or an external library that your software uses.
FBSession.m
- (BOOL)resume {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
FBUID uid = [[defaults objectForKey:#"FBUserId"] longLongValue];
if (uid) {
NSDate* expirationDate = [defaults objectForKey:#"FBSessionExpires"];
if (!expirationDate || [expirationDate timeIntervalSinceNow] > 0) {
_uid = uid;
_sessionKey = [[defaults stringForKey:#"FBSessionKey"] copy];
_sessionSecret = [[defaults stringForKey:#"FBSessionSecret"] copy];
_expirationDate = [expirationDate retain];
for (id<FBSessionDelegate> delegate in _delegates) {
[delegate session:self didLogin:_uid]; // this is the line where i m getting stuck while looping break
}
return YES;
}
}
return NO;
}
#pragma mark Facebook
- (void)session:(FBSession *)session didLogin:(FBUID)uid{
NSLog(#"Facebook Logged in");
FBStreamDialog *dialog = [[[FBStreamDialog alloc] initWithSession:fbsession] autorelease];
dialog.delegate=self;
Note *note;
NSString *str = [note noteTitle];
dialog.attachment = [NSString stringWithFormat: #"{\"name\" : \"Death Diary Bucket List Item\",\"href\" : \"http://ifidieapp.com\",\"caption\" : \"{*actor*} added a Bucket List Item\",\"description\" : \"%# \",\"media\": [{\"type\": \"image\",\"src\": \"http://deathdiaryapp.com/wp-content/uploads/2010/01/facebook-big-icon.jpg\",\"href\": \"http://ifidieapp.com\"}]}",str];
}
dialog.userMessagePrompt = #"Enter anything about the item here:";
[dialog show];
}
What could be wrong?
not sure why you should have a array of delegate...
if stuck, try the old API:
facebook = [[Facebook alloc] initWithAppId:#"YOUR_APP_ID"];
[facebook dialog:#"stream.publish" andParams:fbArguments andDelegate:self];
easier, faster (for prototyping or light needs.
if you want a specific answer to your issue, please provide more details (where do you initialize your fb object, where do you call FBSession from).
I am developing an iPhone alarm app based on local notifications.
On deleting an alarm, the related local notification should get cancelled. But how can I determine exactly which object from the array of local notifications is to be cancelled?
I am aware of [[UIApplication sharedApplication] cancelLocalNotification:notification] method but how can I get this 'notification' to cancel it?
You can save a unique value for key in your local notification's userinfo.
Get all local notification, loop through the array and delete the particular notification.
Code as follows,
OBJ-C:
UIApplication *app = [UIApplication sharedApplication];
NSArray *eventArray = [app scheduledLocalNotifications];
for (int i=0; i<[eventArray count]; i++)
{
UILocalNotification* oneEvent = [eventArray objectAtIndex:i];
NSDictionary *userInfoCurrent = oneEvent.userInfo;
NSString *uid=[NSString stringWithFormat:#"%#",[userInfoCurrent valueForKey:#"uid"]];
if ([uid isEqualToString:uidtodelete])
{
//Cancelling local notification
[app cancelLocalNotification:oneEvent];
break;
}
}
SWIFT:
var app:UIApplication = UIApplication.sharedApplication()
for oneEvent in app.scheduledLocalNotifications {
var notification = oneEvent as UILocalNotification
let userInfoCurrent = notification.userInfo! as [String:AnyObject]
let uid = userInfoCurrent["uid"]! as String
if uid == uidtodelete {
//Cancelling local notification
app.cancelLocalNotification(notification)
break;
}
}
UserNotification:
If you use UserNotification (iOS 10+), just follow this steps:
When creating the UserNotification content, add an unique identifier
Remove specific pending notification using removePendingNotificationRequests(withIdentifiers:)
Remove specific delivered notification using removeDeliveredNotifications(withIdentifiers:)
For more info, UNUserNotificationCenter
Other Option:
First of All, when you create local notification, you can store it in user defaults for future use, Local notification object can not be stored directly in user defaults, This object needs to be converted into NSData object first, and then NSData can be stored into User defaults. Below is code for that:
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:localNotif];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:[NSString stringWithFormat:#"%d",indexPath.row]];
After you have stored and scheduled local notification, In future, requirement may arise that you need to cancel any of notification that you created earlier, So you can retrieve it from User defaults.
NSData *data= [[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:#"%d",UniqueKey]];
UILocalNotification *localNotif = [NSKeyedUnarchiver unarchiveObjectWithData:data];
NSLog(#"Remove localnotification are %#", localNotif);
[[UIApplication sharedApplication] cancelLocalNotification:localNotif];
[[NSUserDefaults standardUserDefaults] removeObjectForKey:[NSString stringWithFormat:#"%d",UniqueKey]];
Hope This helps
Here is what i do.
When creating your notification do this:
// Create the notification
UILocalNotification *notification = [[UILocalNotification alloc] init] ;
notification.fireDate = alertDate;
notification.timeZone = [NSTimeZone localTimeZone] ;
notification.alertAction = NSLocalizedString(#"Start", #"Start");
notification.alertBody = **notificationTitle**;
notification.repeatInterval= NSMinuteCalendarUnit;
notification.soundName=UILocalNotificationDefaultSoundName;
notification.applicationIconBadgeNumber = 1;
[[UIApplication sharedApplication] scheduleLocalNotification:notification] ;
when trying to delete it do this:
NSArray *arrayOfLocalNotifications = [[UIApplication sharedApplication] scheduledLocalNotifications] ;
for (UILocalNotification *localNotification in arrayOfLocalNotifications) {
if ([localNotification.alertBody isEqualToString:savedTitle]) {
NSLog(#"the notification this is canceld is %#", localNotification.alertBody);
[[UIApplication sharedApplication] cancelLocalNotification:localNotification] ; // delete the notification from the system
}
}
This solution should work for multiple notifications, and your not managing any arrays or dictionaries or user defaults. Your simply using the data you've already saved to the systems notification database.
Hope this helps future designers and developers.
Happy coding guys! :D
Scheduling and removeNotification in swift:
static func scheduleNotification(notificationTitle:String, objectId:String) {
var localNotification = UILocalNotification()
localNotification.fireDate = NSDate(timeIntervalSinceNow: 24*60*60)
localNotification.alertBody = notificationTitle
localNotification.timeZone = NSTimeZone.defaultTimeZone()
localNotification.applicationIconBadgeNumber = 1
//play a sound
localNotification.soundName = UILocalNotificationDefaultSoundName;
localNotification.alertAction = "View"
var infoDict : Dictionary<String,String!> = ["objectId" : objectId]
localNotification.userInfo = infoDict;
UIApplication.sharedApplication().scheduleLocalNotification(localNotification)
}
static func removeNotification(objectId:String) {
var app:UIApplication = UIApplication.sharedApplication()
for event in app.scheduledLocalNotifications {
var notification = event as! UILocalNotification
var userInfo:Dictionary<String,String!> = notification.userInfo as! Dictionary<String,String!>
var infoDict : Dictionary = notification.userInfo as! Dictionary<String,String!>
var notifcationObjectId : String = infoDict["objectId"]!
if notifcationObjectId == objectId {
app.cancelLocalNotification(notification)
}
}
}
Swift 4 solution:
UNUserNotificationCenter.current().getPendingNotificationRequests { (requests) in
for request in requests {
if request.identifier == "identifier" {
UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: ["identifier"])
}
}
}
iMOBDEV's solution works perfectly to remove a specific notification (e.g. after deleting the alarm) but it's specially useful when you need to selectively remove any notification that has already fired and is still on the notification center.
A possible scenario would be: the notification for an alarm fires, but the user opens the app without tapping on that notification and schedules that alarm again.
If you want to make sure only one notification can be on the notification center for a given item/alarm, it's a good approach. It also allows you not having to clear all notifications every time the app is opened, shall that fit the app better.
Upon creating a local notification, use NSKeyedArchiver to store it as Data in UserDefaults. You can create a key equal to what you're saving in the notification's userInfo dictionary. If it's associated with a Core Data object, you could use its unique objectID property.
Retrieve it with NSKeyedUnarchiver. Now you're able to delete it using the cancelLocalNotification method.
Update the key on UserDefaults accordingly.
Here's a Swift 3.1 version of that solution (for targets below iOS 10):
Store
// localNotification is the UILocalNotification you've just set up
UIApplication.shared.scheduleLocalNotification(localNotification)
let notificationData = NSKeyedArchiver.archivedData(withRootObject: localNotification)
UserDefaults.standard.set(notificationData, forKey: "someKeyChosenByYou")
Retrieve and delete
let userDefaults = UserDefaults.standard
if let existingNotificationData = userDefaults.object(forKey: "someKeyChosenByYou") as? Data,
let existingNotification = NSKeyedUnarchiver.unarchiveObject(with: existingNotificationData) as? UILocalNotification {
// Cancel notification if scheduled, delete it from notification center if already delivered
UIApplication.shared.cancelLocalNotification(existingNotification)
// Clean up
userDefaults.removeObject(forKey: "someKeyChosenByYou")
}
Swift Version, if need:
func cancelLocalNotification(UNIQUE_ID: String){
var notifyCancel = UILocalNotification()
var notifyArray = UIApplication.sharedApplication().scheduledLocalNotifications
for notifyCancel in notifyArray as! [UILocalNotification]{
let info: [String: String] = notifyCancel.userInfo as! [String: String]
if info[uniqueId] == uniqueId{
UIApplication.sharedApplication().cancelLocalNotification(notifyCancel)
}else{
println("No Local Notification Found!")
}
}
}
You can keep a string with the category identifier when scheduling the notification like so
localNotification.category = NotificationHelper.categoryIdentifier
and search for it and cancel when needed like so
let app = UIApplication.sharedApplication()
for notification in app.scheduledLocalNotifications! {
if let cat = notification.category{
if cat==NotificationHelper.categoryIdentifier {
app.cancelLocalNotification(notification)
break
}
}
}
swift 3-style:
final private func cancelLocalNotificationsIfIOS9(){
//UIApplication.shared.cancelAllLocalNotifications()
let app = UIApplication.shared
guard let notifs = app.scheduledLocalNotifications else{
return
}
for oneEvent in notifs {
let notification = oneEvent as UILocalNotification
if let userInfoCurrent = notification.userInfo as? [String:AnyObject], let uid = userInfoCurrent["uid"] as? String{
if uid == uidtodelete {
//Cancelling local notification
app.cancelLocalNotification(notification)
break;
}
}
}
}
for iOS 10 use:
let center = UNUserNotificationCenter.current()
center.removePendingNotificationRequests(withIdentifiers: [uidtodelete])
The UILocalNotification object you pass to cancelLocalNotification: will match any existing UILocalNotification object with matching properties.
So:
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.alertBody = #"foo";
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
will present a local notification that can later be cancelled with:
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.alertBody = #"foo";
[[UIApplication sharedApplication] cancelLocalNotification:notification];
I use this function in Swift 2.0:
static func DeleteNotificationByUUID(uidToDelete: String) -> Bool {
let app:UIApplication = UIApplication.sharedApplication()
// loop on all the current schedualed notifications
for schedualedNotif in app.scheduledLocalNotifications! {
let notification = schedualedNotif as UILocalNotification
let urrentUi = notification.userInfo! as! [String:AnyObject]
let currentUid = urrentUi["uid"]! as! String
if currentUid == uidToDelete {
app.cancelLocalNotification(notification)
return true
}
}
return false
}
Inspired from #KingofBliss's Answer
For Repeated Reminders ( For example you want your alarm to fire on Sun, Sat and Wed at 4 PM , Then you have to make 3 alarms and set repeatInterval to NSWeekCalendarUnit ).
For making Once Only Reminder :
UILocalNotification *aNotification = [[UILocalNotification alloc] init];
aNotification.timeZone = [NSTimeZone defaultTimeZone];
aNotification.alertBody = _reminderTitle.text;
aNotification.alertAction = #"Show me!";
aNotification.soundName = UILocalNotificationDefaultSoundName;
aNotification.applicationIconBadgeNumber += 1;
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *componentsForFireDate = [calendar components:(NSYearCalendarUnit | NSWeekCalendarUnit| NSHourCalendarUnit | NSMinuteCalendarUnit| NSSecondCalendarUnit | NSWeekdayCalendarUnit) fromDate: _reminderDate];
[componentsForFireDate setHour: [componentsForFireDate hour]] ; //for fixing 8PM hour
[componentsForFireDate setMinute:[componentsForFireDate minute]];
[componentsForFireDate setSecond:0] ;
NSDate *fireDateOfNotification = [calendar dateFromComponents: componentsForFireDate];
aNotification.fireDate = fireDateOfNotification;
NSDictionary *infoDict = [NSDictionary dictionaryWithObject:_reminderTitle.text forKey:kRemindMeNotificationDataKey];
aNotification.userInfo = infoDict;
[[UIApplication sharedApplication] scheduleLocalNotification:aNotification];
For Making Repeated Reminder :
for (int i = 0 ; i <reminderDaysArr.count; i++)
{
UILocalNotification *aNotification = [[UILocalNotification alloc] init];
aNotification.timeZone = [NSTimeZone defaultTimeZone];
aNotification.alertBody = _reminderTitle.text;
aNotification.alertAction = #"Show me!";
aNotification.soundName = UILocalNotificationDefaultSoundName;
aNotification.applicationIconBadgeNumber += 1;
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *componentsForFireDate = [calendar components:(NSYearCalendarUnit | NSWeekCalendarUnit| NSHourCalendarUnit | NSMinuteCalendarUnit| NSSecondCalendarUnit | NSWeekdayCalendarUnit) fromDate: _reminderDate];
[componentsForFireDate setWeekday: [[reminderDaysArr objectAtIndex:i]integerValue]];
[componentsForFireDate setHour: [componentsForFireDate hour]] ; // Setup Your Own Time.
[componentsForFireDate setMinute:[componentsForFireDate minute]];
[componentsForFireDate setSecond:0] ;
NSDate *fireDateOfNotification = [calendar dateFromComponents: componentsForFireDate];
aNotification.fireDate = fireDateOfNotification;
aNotification.repeatInterval = NSWeekCalendarUnit;
NSDictionary *infoDict = [NSDictionary dictionaryWithObject:_reminderTitle.text forKey:kRemindMeNotificationDataKey];
aNotification.userInfo = infoDict;
[[UIApplication sharedApplication] scheduleLocalNotification:aNotification];
}
}
For Filtering you array to display it.
-(void)filterNotficationsArray:(NSMutableArray*) notificationArray{
_dataArray = [[NSMutableArray alloc]initWithArray:[[UIApplication sharedApplication] scheduledLocalNotifications]];
NSMutableArray *uniqueArray = [NSMutableArray array];
NSMutableSet *names = [NSMutableSet set];
for (int i = 0 ; i<_dataArray.count; i++) {
UILocalNotification *localNotification = [_dataArray objectAtIndex:i];
NSString * infoDict = [localNotification.userInfo objectForKey:#"kRemindMeNotificationDataKey"];
if (![names containsObject:infoDict]) {
[uniqueArray addObject:localNotification];
[names addObject:infoDict];
}
}
_dataArray = uniqueArray;
}
To remove Reminder even it was Once Only or Repeated :
- (void) removereminder:(UILocalNotification*)notification
{
_dataArray = [[NSMutableArray alloc]initWithArray:[[UIApplication sharedApplication]scheduledLocalNotifications]];
NSString * idToDelete = [notification.userInfo objectForKey:#"kRemindMeNotificationDataKey"];
for (int i = 0 ; i<_dataArray.count; i++)
{
UILocalNotification *currentLocalNotification = [_dataArray objectAtIndex:i];
NSString * notificationId = [currentLocalNotification.userInfo objectForKey:#"kRemindMeNotificationDataKey"];
if ([notificationId isEqualToString:idToDelete])
[[UIApplication sharedApplication]cancelLocalNotification:currentLocalNotification];
}
_dataArray = [[NSMutableArray alloc]initWithArray:[[UIApplication sharedApplication]scheduledLocalNotifications]];
[self filterNotficationsArray:_dataArray];
[_remindersTV reloadData];
}
I expanded on KingofBliss's answer a little, written this a little more Swift2-like, removed some unnecessary code, and added in some crash guards.
To start, when creating the notification, you need to make sure you set the uid (or any custom property really) of the notification's userInfo:
notification.userInfo = ["uid": uniqueid]
Then, when deleting it, you can do:
guard
let app: UIApplication = UIApplication.sharedApplication(),
let notifications = app.scheduledLocalNotifications else { return }
for notification in notifications {
if
let userInfo = notification.userInfo,
let uid: String = userInfo["uid"] as? String where uid == uidtodelete {
app.cancelLocalNotification(notification)
print("Deleted local notification for '\(uidtodelete)'")
}
}
Delete already delivered notification Swift5
UNUserNotificationCenter.current().getDeliveredNotifications{ (requests) in
for request in requests {
if request.request.identifier == "identifier"{
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: ["identifier"])
}
}
}