Why are there no times in any of my GDataEntryCalendarEvent? - objective-c

I am using a GDataServiceGoogleCalendar to anonymously fetch a GDataFeedCalendarEvent from a public url. But I am absolutely unable to retrieve times from any of the resulting GDataEntryCalendarEvent objects. I can read the title, so I believe the API works, but somehow the times arrays are lost somewhere.
The service is instantiated as follows:
- (GDataServiceGoogleCalendar *)calendarService {
static GDataServiceGoogleCalendar* service = nil;
if (!service) {
service = [[GDataServiceGoogleCalendar alloc] init];
[service setShouldCacheResponseData:YES];
[service setServiceShouldFollowNextLinks:YES];
[service setIsServiceRetryEnabled:YES];
}
return service;
}
This is the code where the data is retrieved:
for (GDataEntryCalendarEvent *event in eventEntries) {
NSString *title = [[event title] stringValue];
GDataDateTime *startTime = nil;
GDataDateTime *endTime = nil;
NSArray *times = [event times];
GDataWhen *when = nil;
if ([times count] > 0) {
when = [times objectAtIndex:0];
startTime = [when startTime];
endTime = [when endTime];
}
}
What is wrong with my code or the way I connect? The sample app retrieves the dates successfully.

I am sorry but I can not answer what is wrong with your code. I had problems with the date of the events, and that was my solution that works great for me:
Hope it will help you:
NSArray *events = [feed entries];
[events enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
GDataEntryEvent *entry = [events objectAtIndex:idx];
for (NSUInteger i=0; i<[[entry times] count]; i++) {
NSDate * startDate = [[[[entry times] objectAtIndex:i] startTime] date];
NSDate * endDate = [[[[entry times] objectAtIndex:i] endTime] date];
}
}];
There might be a better way but this works.

The Google API requires the use of an actual identified user even to access the public data.
So no access to most API call s is granted until an authenticated user account is being used.

Related

TableView doesn't show uiimage

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.

FIlter alassets by year

I'm trying to filter AlAssets by year and month. I can already get the dates and filter by year and month, but it's too slow with about 1000 photos. What's the best way to do it?
+ (void) loadFromLibraryByDate:(ALAssetsLibrary *)library assetType:(NSString *)type toArray:(NSMutableArray *)array onTable:(UITableView *)tableView onYear:(NSString *)year onMonth:(NSString *)mouth withDelegate:(id) delegate{
//clean passed objects
[array removeAllObjects];
// filter for the library
NSInteger groupType = ALAssetsGroupAll;
// block to enumerate thought the groups
ALAssetsLibraryGroupsEnumerationResultsBlock listGroupBlock =
^(ALAssetsGroup *group, BOOL *stop){
if(group){
[group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop){
if(asset){
// cachedPhotos = [NSMutableDictionary new];
if([asset valueForProperty:ALAssetPropertyType] == type){
if(year != nil && mouth != nil)
{
NSDate *date = [asset valueForProperty:ALAssetPropertyDate];
if(date.year == [year integerValue] && date.month == [mouth integerValue])
{
[array addObject:asset];
}
}
else if(year != nil && mouth == nil)
{
NSDate *date = [asset valueForProperty:ALAssetPropertyDate];
NSString *monthName = [date monthName:date.month];
if(date.year == [year integerValue])
{
if(![array containsObject:monthName])
{
[array addObject:monthName];
}
}
}
else
{
NSDate *date = [asset valueForProperty:ALAssetPropertyDate];
NSNumber *yearNum = [NSNumber numberWithInt:date.year];
if(![array containsObject:yearNum])
{
[array addObject:yearNum];
}
}
}
}
}];
}
else{
if( [delegate respondsToSelector:#selector(didFinishLoadingLibraryByDate:)] ){
[delegate performSelector:#selector(didFinishLoadingLibraryByDate:)];
}
[tableView reloadData];
}
};
// failure block, what happens if when something wrong happens when enumerating
ALAssetsLibraryAccessFailureBlock failBlock = ^(NSError *error){
NSLog(#"Error: %#", [error localizedDescription]);
static dispatch_once_t pred;
dispatch_once(&pred, ^{
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *libraryFailure = [[UIAlertView alloc] initWithTitle:#"Serviço de Localização" message:#"Para poder partilhar conteúdos nesta versão iOS, tem de autorizar os serviços de localização. (Definições > Serviços de Localização)" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[libraryFailure show];
[libraryFailure release];
});
});
};
[library enumerateGroupsWithTypes:groupType usingBlock:listGroupBlock failureBlock:failBlock];
Any help appreciated, thanks
I think you're on the right track. There is no way I know of to filter on metadata except by enumerating the way you are doing it. Unfortunately, enumerating through asset groups is just inherently slow on iOS -- if you think 1000 is bad, try 10k or 20k assets (not at all uncommon, I have that on my carry phone right now).
One way around this (not necessarily advised, as it's a lot of work and the bug potential is very high) is to build your own database of asset timestamps. While the user is otherwise busy (with a tutorial or something), enumerate over all the assets and copy the metadata and ALAssetPropertyAssetURL to whatever format works best for you. Don't forget to listen for ALAssetsLibraryChangedNotification messages if you do this.
You should enumerate all ALAsset first When App launching,and then filter them. Because Enumerating ALAsset from database is so slow, so you should not reenumerate them again.
Therer is a notice, reenumerate ALAsset more faster then the first. Apple should optimize the library.

iOS XMPP framework get all registered users

In my chat application I want to get all online registered users. So everybody and not only people in my roster which is achieved with this code:
- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence {
// a buddy went offline/online
NSString *presenceType = [presence type]; // online/offline
NSString *myUsername = [[sender myJID] user];
NSString *presenceFromUser = [[presence from] user];
if (![presenceFromUser isEqualToString:myUsername]) {
if ([presenceType isEqualToString:#"available"]) {
[_chatDelegate newBuddyOnline:[NSString stringWithFormat:#"%##%#", presenceFromUser, #"chat.denederlandsewateren.nl"]];
} else if ([presenceType isEqualToString:#"unavailable"]) {
[_chatDelegate buddyWentOffline:[NSString stringWithFormat:#"%##%#", presenceFromUser, #"chat.denederlandsewateren.nl"]];
}
}
}
With this code the users only sees other users who are 'friends' but I need all users registered on this particular domain. Is this possible with ejabberd?
- (void)getAllRegisteredUsers {
NSError *error = [[NSError alloc] init];
NSXMLElement *query = [[NSXMLElement alloc] initWithXMLString:#"<query xmlns='http://jabber.org/protocol/disco#items' node='all users'/>"
error:&error];
XMPPIQ *iq = [XMPPIQ iqWithType:#"get"
to:[XMPPJID jidWithString:#"DOMAIN"]
elementID:[xmppStream generateUUID] child:query];
[xmppStream sendElement:iq];
}
- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq
{
NSXMLElement *queryElement = [iq elementForName: #"query" xmlns: #"http://jabber.org/protocol/disco#items"];
if (queryElement) {
NSArray *itemElements = [queryElement elementsForName: #"item"];
NSMutableArray *mArray = [[NSMutableArray alloc] init];
for (int i=0; i<[itemElements count]; i++) {
NSString *jid=[[[itemElements objectAtIndex:i] attributeForName:#"jid"] stringValue];
[mArray addObject:jid];
}
}
I had the same issue, I got queryElement as nil as well. I've changed the response code to see the XML like this:
- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq
{
//DDLogVerbose(#"%#: %# - %#", THIS_FILE, THIS_METHOD, [iq elementID]);
//NSXMLElement *queryElement = [iq elementForName:#"query" xmlns: #"http://jabber.org/protocol/disco#items"];
NSXMLElement *queryElement = [iq elementForName:#"query" xmlns: #"jabber:iq:roster"];
NSLog(#"IQ: %#",iq);
if (queryElement) {
NSArray *itemElements = [queryElement elementsForName: #"item"];
NSMutableArray *mArray = [[NSMutableArray alloc] init];
for (int i=0; i<[itemElements count]; i++) {
NSString *jid=[[[itemElements objectAtIndex:i] attributeForName:#"jid"] stringValue];
NSLog(#"%#",jid);
[mArray addObject:jid];
}
}
return NO;
}
As you may see what I've changed is the xmlns: from this xmlns: #"http://jabber.org/protocol/disco#items" to this xmlns: #"jabber:iq:roster" and that gave me the list of users.
I'm using ejabberd, not sure if this works for all the others XMPP servers.
Also I've found that this gave me the list of the "buddy" users, looks like if you want "all" users you need to make the query as an admin user. Please check this link for more information about it: https://www.ejabberd.im/node/3420
After googling, You can not get all user easily, You must need to create Shared Roster Groups by follow step in the Example 1: everybody can see everybody else after done this you will get all the online users in the below delegate methods.
- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence

Checking for duplicated items before adding new event in iOS - EKEventStore

I'm new to iOS programming and I am working on a easy project that lists holidays from a given city and gives users the ability to add those events to the iCal default calendar.
The issue is: how to check if there is already an event with same properties (title and start date for example) in the user's calendar. This could happen if the action button (used to add an event to iCal) is pressed more than once. In such a situation, I don't want two or more identical events being created in iCal.
I have tried to use NSPredicate but I am totally lost on how to get it sorted.
Any help would come be appreciated!
Thanks in advance.
Bellow is my event-adding code just to make things clear. In this case a user is adding multiple events from a list (all local holidays for example).
for (int i = 0; i<[allHolidayNames count]; ++i) {
// ------ EVENT MANIPULATION ------
EKEventStore *eventStore = [[EKEventStore alloc] init];
EKEvent *addEvent = [EKEvent eventWithEventStore:eventStore];
addEvent.title = [allHolidayNames objectAtIndex:i];
addEvent.startDate = [allHolidayDates objectAtIndex:i];
addEvent.allDay = YES;
[addEvent setCalendar:[eventStore defaultCalendarForNewEvents]];
[eventStore saveEvent:addEvent span:EKSpanThisEvent commit:YES error:nil];
}
Summary
At some point in your instance method (probably during the for loop) you will want to create an NSPredicate based on [allHolidayDates objectAtIndex:i] to return an array that you loop through to check if [allHolidayNames objectAtIndex:i] is present in the returned events.
Example code
for (int i = 0; i<[allHolidayNames count]; ++i) {
// ------ EVENT MANIPULATION ------
EKEventStore *eventStore = [[EKEventStore alloc] init];
NSPredicate *predicateForEventsOnHolidayDate = [eventStore predicateForEventsWithStartDate:[allHolidayDates objectAtIndex:i] endDate:[allHolidayDates objectAtIndex:i] calendars:nil]; // nil will search through all calendars
NSArray *eventsOnHolidayDate = [eventStore eventsMatchingPredicate:predicateForEventsOnHolidayDate]
BOOL eventExists = NO;
for (EKEvent *eventToCheck in eventsOnHolidayDate) {
if ([eventToCheck.title isEqualToString:[allHolidayNames objectAtIndex:i]]) {
eventExists = YES;
}
}
if (eventExists == NO) {
EKEvent *addEvent = [EKEvent eventWithEventStore:eventStore];
addEvent.title = [allHolidayNames objectAtIndex:i];
addEvent.startDate = [allHolidayDates objectAtIndex:i];
addEvent.allDay = YES;
[addEvent setCalendar:[eventStore defaultCalendarForNewEvents]];
[eventStore saveEvent:addEvent span:EKSpanThisEvent commit:YES error:nil];
}
}
Tips
To help visualise the data, especially the contents of arrays and objects, try using NSLog. This will output the contents of an object to the console to help you understand the data structures a bit better.
NSLog("eventsOnHolidayDate = %#",eventsOnHolidayDate);
Note that eventsMatchingPredicate will block the main thread whilst retrieving events. If your doing this multiple times in a row it could impact on the user experience. You should consider using enumerateEventsMatchingPredicate:usingBlock: (outside the scope of this question).

Memory errors when trying to create and populate a NSMutableDictionary

I am not a Cocoa developer, but I have been dabbling in it to build some plugins for PhoneGap. This particular plugin method is either 1) crashing the app without saying why or 2) complaining about how I release/don't release an object. I have tried a ton of things on my end, including using an Enumerator instead of the for loop. If anyone can point me in the right direction, that would be awesome. I don't mind legwork:
- (void)getPreferences:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options {
NSUInteger argc = [arguments count];
NSString* jsCallback = nil;
if (argc > 0) {
jsCallback = [arguments objectAtIndex:0];
} else {
NSLog(#"Preferences.getPreferences: Missing 1st parameter.");
return;
}
NSDictionary *defaults = [[NSUserDefaults standardUserDefaults] dictionaryRepresentation];
NSMutableArray *keys = (NSMutableArray *) [options objectForKey:#"keys"];
NSMutableDictionary *values = [[NSMutableDictionary alloc] init];
NSUInteger ky = [keys count];
for (int i = 0; i < ky; i ++) {
#try {
[values setObject:[defaults objectForKey:[keys objectAtIndex:i]] forKey:[keys objectAtIndex:i]];
}
#catch (NSException * err) {
NSLog(#"Error %#", err);
}
}
[keys release];
NSString* jsString = [[NSString alloc] initWithFormat:#"%#(%#);", jsCallback, [values JSONRepresentation]];
[defaults release];
[values release];
[webView stringByEvaluatingJavaScriptFromString:jsString];
[jsString release];
}
Human version:
options contains a dictionary with a single key of "keys"
that key contains an array of strings (that are going to be used as keys for lookup)
I want to loop through that array and
For every value that exists in defaults for that key, copy it to values using the same key
Finally, I want to send that values back as JSON (This part was working when I just passed the entire defaults object in, so I think the JSON method is working)
From your code, it follows that you 'own' objects values and jsString (the ones you created with alloc), so you should release them and not any other.
You can read more on memory management here.
Is this the whole code? Also, what exactly error do you get?
Nikita is right, it looks as though you're overreleasing defaults, which would cause a crash later when the autorelease pool gets released. Also, if I understand what you're trying to do correctly, you could create the values dictionary with a single line of code:
NSDictionary *values = [defaultsDict dictionaryWithValuesForKeys:keys];