在ARC中收到内存警告

时间:2014-01-08 08:34:09

标签: ios objective-c multithreading ekevent ekeventstore

我正在调用syncWithCalendar,并且在成功添加事件后,我得到内存不足警告,并且应用程序以“Received Low Memory”警告终止。在日历中生成和保存的事件超过50个。我尝试使用仪器,但我无法找到发生内存泄漏的代码,也无法通过仪器中显示的实时字节找到我无法跟踪导致泄漏。任何人都可以帮我解决这个问题。

- (void)syncWithCalendar
{
    @autoreleasepool {
        [self deleteEventsIfExist];

        NSMutableDictionary *dictionary = [util readPListData];
        NSMutableArray *courses = [util getCourses];
        __block NSMutableArray *lessons;
        __block NSMutableDictionary *lesson;
        NSString *studentID = [util getProgramDetails].studentId;
        NSString *programName = [util getProgramDetails].programName;

        double offset[] = {0, 0, -300, -900, -1800, -3600, -7200, -86400, -172800};

        __block NSString *startDateString = @"", *endDateString = @"";
        NSTimeInterval relativeOffsetValue = 0;
        int index = [[dictionary objectForKey:@"event-alert-option"] intValue];

        relativeOffsetValue = offset[index];

        NSDateFormatter *formatter;
        formatter = [[NSDateFormatter alloc] init];
        [formatter setDateFormat:@"MM/dd/yyyy HH:mm:ss"];
        [formatter setDateFormat:@"MM/dd/yyyy"];

        NSString *currentDateString = [NSString stringWithFormat:@"%@ 09:00:00", [formatter        stringFromDate:[NSDate date]]];
        [formatter setDateFormat:@"MM/dd/yyyy HH:mm:ss"];

        NSDate *currentDate = [formatter dateFromString:currentDateString];

        EKEventStore *eventStore = [[EKEventStore alloc] init];

        if([eventStore respondsToSelector:@selector(requestAccessToEntityType:completion:)]) {
            // iOS 6 and later
            [eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
                if (granted){
                    //---- codes here when user allow your app to access theirs' calendar.

                    dispatch_async(dispatch_get_main_queue(), ^{
                        // Event creation code here.
                        for (int i=0; i<[courses count]; i++)
                        {
                            @autoreleasepool {
                                lessons = [[courses objectAtIndex:i] objectForKey:@"lessons"];
                                for (int j=0; j<[lessons count]; j++)
                                {
                                    @autoreleasepool {
                                        lesson = [lessons objectAtIndex:j];
                                        NSString *title = nil;
                                        title = [NSString stringWithFormat:@"%@ %@-Complete %@ lesson",studentID,programName,[lesson objectForKey:@"lesson-name"]];

                                        if ([[lesson objectForKey:@"actual-exam-date"] isEqualToString:@"00/00/0000"])
                                        {
                                            startDateString = [NSString stringWithFormat:@"%@ %@", [lesson objectForKey:@"plan-exam-date"], @"09:00:00"];
                                            endDateString = [NSString stringWithFormat:@"%@ %@", [lesson objectForKey:@"plan-exam-date"], @"18:00:00"];
                                        }
                                        else
                                        {
                                            if ([[lesson objectForKey:@"retake-actual-date"] isEqualToString:@"00/00/0000"])
                                            {
                                                startDateString = [NSString stringWithFormat:@"%@ %@", [lesson objectForKey:@"retake-plan-date"], @"09:00:00"];
                                                endDateString = [NSString stringWithFormat:@"%@ %@", [lesson objectForKey:@"retake-plan-date"], @"18:00:00"];
                                            }
                                        }

                                        if (!([startDateString isEqualToString:@""] && [endDateString isEqualToString:@""]))
                                        {
                                            EKEvent *event = [EKEvent eventWithEventStore:eventStore];
                                            event.title=title;
                                            event.startDate = [formatter dateFromString:startDateString];
                                            event.endDate = [formatter dateFromString:endDateString];
                                            event.allDay = NO;
                                            if (index != 0)
                                            {
                                                event.alarms = [NSArray arrayWithObjects:[EKAlarm alarmWithRelativeOffset:relativeOffsetValue], nil];
                                            }
                                            [event setCalendar:[eventStore defaultCalendarForNewEvents]];
                                            // Compare current date to event start date, if start date has been passed then preventing to sync with calendar
                                            NSComparisonResult result = [event.startDate compare:currentDate];
                                            if (result != NSOrderedAscending)
                                            {
                                                NSError *err = nil;
                                                [eventStore saveEvent:event span:EKSpanThisEvent commit:YES error:&err];
                                                if (err) {
                                                    NSLog(@"event not saved .. error = %@",err);
                                                } else {
                                                    NSLog(@"event added successfully");
                                                }
                                            }
                                        }
                                    } // autoreleasepool
                                } // lessons for loop
                            } // autoreleasepool

                        } // courses for loop
                        [self hideModal];
                    });
                }else
                {
                    //----- codes here when user NOT allow your app to access the calendar.
                    //           [self performSelectorOnMainThread:@selector(hideModal) withObject:nil waitUntilDone:NO];
                }
            }];
        } else {
            // sync calendar for <iOS6

        }

    } // autoreleasepool
}  


- (void)deleteEventsIfExist
{  
    @autoreleasepool {  
        NSMutableArray *courses = [util getCourses];  
        __block NSMutableArray *lessons;  
        __block NSMutableDictionary *lesson;  
        NSString *studentID = [util getProgramDetails].studentId;   
        NSString *programName = [util getProgramDetails].programName;   

        EKEventStore* store = [[EKEventStore alloc] init];
        dispatch_async(dispatch_get_main_queue(), ^{  
            // Event creation code here.  
            NSDate* endDate =  [NSDate dateWithTimeIntervalSinceNow:[[NSDate distantFuture] timeIntervalSinceReferenceDate]];  
            NSPredicate *fetchCalendarEvents = [store predicateForEventsWithStartDate:[NSDate date] endDate:endDate calendars:store.calendars];  

            NSArray *allEvents = [store eventsMatchingPredicate:fetchCalendarEvents];

            for (int i=0; i<[courses count]; i++)
            {
                @autoreleasepool {
                    lessons = [[courses objectAtIndex:i] objectForKey:@"lessons"];
                    for (int j=0; j<[lessons count]; j++)
                    {
                        @autoreleasepool {
                            lesson = [lessons objectAtIndex:j];

                            NSString *oldEventSubtitle = [NSString stringWithFormat:@"%@ %@-Complete %@ lesson",studentID,programName,[lesson objectForKey:@"lesson-name"]];
                            for (EKEvent *e in allEvents)
                            {
                                if ( [oldEventSubtitle isEqualToString:e.title])
                                {
                                    NSError* error = nil;
                                    [store removeEvent:e span:EKSpanThisEvent commit:YES error:&error];
                                    NSLog(@"deleting events");
                                }
                            }
                        } // autoreleasepool

                    } // lessons

                } // autoreleasepool

            } // courses
        });

    } // autoreleasepool
}

3 个答案:

答案 0 :(得分:0)

您需要在收到内存警告时清除缓存,使用此方法可以帮助您。

-(void)applicationDidReceiveMemoryWarning:(UIApplication *)application {

    [[NSURLCache sharedURLCache] removeAllCachedResponses];
}

答案 1 :(得分:0)

这是一个粗略的猜测,但似乎异步调用可能会导致麻烦。

为了测试这一点,只需使用dispatch_sync而不是dispatch_async并检查内存消耗。如果这会带来改进,那么就会出现一个解决方案,其中包括重新考虑当前的异步“并行”方法,并将其转换为适当的异步“串行”方法或完整的同步方法。

这可能还需要“序列化”此异步方法的所有调用:

[eventStore requestAccessToEntityType:EKEntityTypeEvent 
                           completion:^(BOOL granted, NSError *error) {
   ...
}]

答案 2 :(得分:0)

这就是我调用syncWithCalendar函数

的方法
if([eventStore respondsToSelector:@selector(requestAccessToEntityType:completion:)]) {
// iOS 6 and later
[eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted,
NSError *error) {
if (granted){
dispatch_async(dispatch_get_main_queue(), ^{
[self syncWithCalendar];
});
} else {
// calendar access not granted     
}
}];
}

syncWithCalendar函数中,除了代码行之外,一切都保持不变 正在创建崩溃/内存问题。下面是我不正确的代码行 使用较早的

// wrong
[self.eventstore saveEvent:event span:EKSpanThisEvent commit:YES error:&err];

保存事件的正确方法:(注意:在我的情况下我不需要事件标识符)

// correct
[self.eventstore saveEvent:event span:EKSpanThisEvent commit:NO error:&err]; 

然后在保存所有事件后使用[self.eventstore commit:NULL]。这阻止了我的崩溃。希望这篇文章能够 帮助其他人获得解决方案。谢谢!!!!