Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

oo7ml

macrumors 6502
Original poster
Jan 20, 2010
259
0
Hi,

I have been using Parse.com for the last few months now.

I think Parse servers are now powering over 200,000 apps.

The service they provide is excellent, however i find their servers to be very slow, and therefore my app can get very slow to load content. I am surprised that they don't have a premium tier leveled model so that you can pay for a faster connection / server.

Can anyone recommend a good hosting / server provider for running a Instant Messaging type app?

Thanks in advance for your help.
 
Are you sure it isn't just your internet connection. In my experience the response time has been very quick, on both iOS and android devices.
 
I suppose it depends on the type of app you have. Mine is an instant messaging app so the messages really need to be instant.
 
So it really is your app, not parse servers.

For a chat app to work with parse, you would need a timer running every X seconds, querying for new messages. So this is the bottleneck, the query is going to be pretty much instant but then the app is going to wait another X seconds until it queries again for new messages.

The same is going to happen even on your own custom server on localhost if you don't change your logic. Parse makes it really simple to build a chat app(not instant messaging app), but you are the one who have to query for new messages as opposed to the server telling you a new message has arrived.

I am sorry but there is no easy way to build an instant messaging app. You probably want to look into XMPP.
 
So it really is your app, not parse servers.

For a chat app to work with parse, you would need a timer running every X seconds, querying for new messages. So this is the bottleneck, the query is going to be pretty much instant but then the app is going to wait another X seconds until it queries again for new messages.

The same is going to happen even on your own custom server on localhost if you don't change your logic. Parse makes it really simple to build a chat app(not instant messaging app), but you are the one who have to query for new messages as opposed to the server telling you a new message has arrived.

I am sorry but there is no easy way to build an instant messaging app. You probably want to look into XMPP.

No, it seems to be Parse. If i have a full 3G connection or WiFi connection, sometimes it can take 5-6 seconds to load 7 text based messages, where as it might only take 0.5 seconds to load the same amount of data (7 messages) an hour later, or an hour before hand. The load time is not consistent (even when loading the same number of messages on the same strength signal), so this would not be the app, but would in fact be the connection to the data
 
No, it seems to be Parse. If i have a full 3G connection or WiFi connection, sometimes it can take 5-6 seconds to load 7 text based messages, where as it might only take 0.5 seconds to load the same amount of data (7 messages) an hour later, or an hour before hand. The load time is not consistent (even when loading the same number of messages on the same strength signal), so this would not be the app, but would in fact be the connection to the data

If you are basing your "connection strength" on how many bars you have, this is wildly inconsistent and you shouldn't assume your connection is just as strong because you have 4 bars now and had 4 bars earlier

Also, given that you sometimes see very fast load times, it leads me to believe that it is your connection, not Parse's servers
 
If you are basing your "connection strength" on how many bars you have, this is wildly inconsistent and you shouldn't assume your connection is just as strong because you have 4 bars now and had 4 bars earlier

Even if i left out my signal and focused on a very strong Wi Fi connection, it's still the same.
 
No, it seems to be Parse. If i have a full 3G connection or WiFi connection, sometimes it can take 5-6 seconds to load 7 text based messages, where as it might only take 0.5 seconds to load the same amount of data (7 messages) an hour later, or an hour before hand. The load time is not consistent (even when loading the same number of messages on the same strength signal), so this would not be the app, but would in fact be the connection to the data

I thought you were asking for help, but now you sound like you know you are talking about and I don't think I can be of further assistance
 
I thought you were asking for help, but now you sound like you know you are talking about and I don't think I can be of further assistance

Yes, i still am looking for help... my question was and is :)

Can anyone recommend a good hosting / server provider for running a Instant Messaging type app?
 
Can anyone recommend a good hosting / server provider for running a Instant Messaging type app?

Linode. Of course you'd have to manage the server yourself so if your Linux skills are sub-par you might need to get someone to help you. But Linode are awesome, I've used them since 2010 and their servers are fast, the network is excellent and the support is top notch.

I really wouldn't bother considering anyone else but if you did want some alternatives I've also used Digital Ocean and RamNode and they have been good as well.

All of these options are unmanaged though. It'll cost more if you want a managed server.
 
Could we possibly see the code you are using to load the parse based messages? I can understand if you don't want to share your secrets, but it could really help. Feel free to hide sensitive info
 
Could we possibly see the code you are using to load the parse based messages? I can understand if you don't want to share your secrets, but it could really help. Feel free to hide sensitive info

Sure, thanks... i'll upload the code when i get home this evening, thanks for your help... it's much appreciated.
 
Hi, here is the code:


Code:
#import "AllTableView.h"

@implementation AllTableView

@synthesize historyDelegate;

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
		_refreshControl = [[UIRefreshControl alloc] init];
		[self addSubview:_refreshControl];
		[_refreshControl addTarget:self action:@selector(initTableData) forControlEvents:UIControlEventValueChanged];
    }
    return self;
}

/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
    // Drawing code
}
*/


- (NSArray *)sortedArray:(NSArray *)array
{
	NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:LOC_TIME ascending:YES];
	return [array sortedArrayUsingDescriptors:[NSArray arrayWithObjects:sortDescriptor, nil]];
}

- (void)initTableData
{
	self.delegate = self;
	self.dataSource = self;
	
	// get server time from local time
	NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
	[dateFormat setTimeZone:[NSTimeZone timeZoneWithName:@"WET"]];
	[dateFormat setDateFormat:@"yyyy-MM-dd HH:mm:ss zzz"];
	NSDate *date = [dateFormat dateFromString:[[NSDate date] description]];
	date = [date dateByAddingTimeInterval:-60*61];
	
	NSLog(@"%@", [date description]);
	
	//_arrayDatas = [[NSMutableArray alloc] init];
	NSMutableArray *tmpArray = [[NSMutableArray alloc] init];
	NSString *usersPhone = [[NSUserDefaults standardUserDefaults] objectForKey:USER_PREFIX];
	
	ShowWaitView1(YES, self);
	[self.historyDelegate hideNoteView:YES];
	
	// received location
	PFQuery *receiveLoc = [PFQuery queryWithClassName:PARSE_TABLE_CALL];
	[receiveLoc whereKey:PARSE_CALL_STATUS equalTo:@"Sent"];
	[receiveLoc whereKey:PARSE_CALL_TO equalTo:usersPhone];
	[receiveLoc whereKey:PARSE_CALL_MODIFIED greaterThan:date];
	
	// received & unread location
	PFQuery *receiveLoc1 = [PFQuery queryWithClassName:PARSE_TABLE_CALL];
	[receiveLoc1 whereKey:PARSE_CALL_STATUS equalTo:@"Sent"];
	[receiveLoc1 whereKey:PARSE_CALL_TO equalTo:usersPhone];
	[receiveLoc1 whereKey:PARSE_CALL_ISOPEN equalTo:@NO];
	
	// sent location
	PFQuery *sentLoc = [PFQuery queryWithClassName:PARSE_TABLE_CALL];
	[sentLoc whereKey:PARSE_CALL_STATUS equalTo:@"Sent"];
	[sentLoc whereKey:PARSE_CALL_FROM equalTo:usersPhone];
	[sentLoc whereKey:PARSE_CALL_MODIFIED greaterThan:date];
	
	// received request
	PFQuery *receiveReq = [PFQuery queryWithClassName:PARSE_TABLE_CALL];
	[receiveReq whereKey:PARSE_CALL_TO equalTo:usersPhone];
	[receiveReq whereKey:PARSE_CALL_STATUS equalTo:@"Request"];
	[receiveReq whereKey:PARSE_CALL_MODIFIED greaterThan:date];
	
	// received & unread request
	PFQuery *receiveReq1 = [PFQuery queryWithClassName:PARSE_TABLE_CALL];
	[receiveReq1 whereKey:PARSE_CALL_TO equalTo:usersPhone];
	[receiveReq1 whereKey:PARSE_CALL_STATUS equalTo:@"Request"];
	[receiveReq1 whereKey:PARSE_CALL_ISOPEN equalTo:@NO];
		
	PFQuery *query = [PFQuery orQueryWithSubqueries:@[receiveLoc, sentLoc, receiveReq, receiveReq1, receiveLoc1]];
	//query.cachePolicy = kPFCachePolicyCacheThenNetwork;
	
	[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
		if (!error) {
			for (PFObject *obj in objects) {
				NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
				
				NSDate *dbDate = (NSDate *)[obj createdAt];
				[dict setObject:dbDate forKey:LOC_TIME];
				
				[dict setObject:obj[PARSE_CALL_FROM] forKey:LOC_PHONE];
				[dict setObject:obj[PARSE_CALL_TO] forKey:LOC_TOPHONE];
				[dict setObject:[self getNameFromPhoneInFriends:obj[PARSE_CALL_FROM]] forKey:LOC_USER];
				[dict setObject:[self getNameFromPhoneInFriends:obj[PARSE_CALL_TO]] forKey:LOC_TONAME];
				[dict setObject:obj[PARSE_CALL_LOCTITLE] forKey:LOC_NAME];
				[dict setObject:obj[PARSE_CALL_LAT] forKey:LOC_LAT];
				[dict setObject:obj[PARSE_CALL_LNG] forKey:LOC_LONG];
				[dict setObject:obj[PARSE_CALL_MSG] forKey:LOC_MSG];
				[dict setObject:obj[PARSE_CALL_ISOPEN] forKey:LOC_ISOPEN];
				[dict setObject:obj[PARSE_CALL_BARPOS] forKey:LOC_BARPOS];
				[dict setObject:obj[PARSE_CALL_STATUS] forKey:PARSE_CALL_STATUS];
				
				if (obj[PARSE_CALL_TRACKING]) {
					[dict setObject:obj[PARSE_CALL_TRACKING] forKey:LOC_TRACKING];
				}
				
				PFFile *imageFile = obj[PARSE_CALL_IMAGE];
				if (imageFile) {
					NSData *data = [imageFile getData];
					[dict setObject:data forKey:LOC_IMAGE];
				}
				
				[tmpArray addObject:dict];
			}
			
			_arrayDatas = [[NSMutableArray alloc] initWithArray:[self sortedArray:tmpArray]];
			
			ShowWaitView1(NO, self);
			[self reloadData];
			
			if (!_arrayDatas.count) {
				[self.historyDelegate hideNoteView:NO];
			}
			
			[_refreshControl endRefreshing];
			
		} else {
			NSLog(@"WARNING: Request query failed");
		}
	}];
}

- (NSString *)getNameFromPhoneInFriends:(NSString *)phone
{
	NSArray *array = [[NSUserDefaults standardUserDefaults] objectForKey:FRIENDS_LIST];
	if (array && array.count) {
		for (NSDictionary *dict in array) {
			if ([[dict objectForKey:LOC_PHONE] isEqualToString:phone]) {
				return [dict objectForKey:LOC_USER];
			}
		}
	}
	
	array = [[NSUserDefaults standardUserDefaults] objectForKey:GUARDIANS_LIST];
	if (array && array.count) {
		for (NSDictionary *dict in array) {
			if ([[dict objectForKey:LOC_PHONE] isEqualToString:phone]) {
				return [dict objectForKey:LOC_USER];
			}
		}
	}
	
	return phone;
}


- (NSString *)dateStringFromToday:(NSDate *)date//(NSString *)dateStr;
{
	/*NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
	 [dateFormat setTimeZone:[NSTimeZone timeZoneWithName:@"CST"]];
	 [dateFormat setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
	 //NSDate *date = [dateFormat dateFromString:dateStr];
	 
	 NSDateFormatter *dateFormat1 = [[NSDateFormatter alloc] init];
	 [dateFormat1 setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
	 NSDate *date = [dateFormat1 dateFromString:[dateFormat stringFromDate:dbDate]];*/
	
	NSString *dateString;
	
	NSCalendar *cal = [NSCalendar currentCalendar];
	NSDateComponents *components, *components1;
	
	// today time
	components = [cal components:(NSEraCalendarUnit|NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit) fromDate:[NSDate date]];
	NSDate *today = [cal dateFromComponents:components];
	
	components1 = [cal components:(NSEraCalendarUnit|NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit) fromDate:date];
	NSDate *other = [cal dateFromComponents:components1];
	
	if([today isEqualToDate:other]) {
		NSDateFormatter *formate = [[NSDateFormatter alloc] init];
		[formate setDateFormat:@"HH:mm"];
		
		dateString = [formate stringFromDate:date];
		return dateString;
		
	} else if (components.day - 1 == components1.day) {
		dateString = @"Yesterday";
		return dateString;
	}
	
	// week time
	components = [cal components:(NSWeekCalendarUnit) fromDate:[NSDate date]];
	today = [cal dateFromComponents:components];
	
	components1 = [cal components:(NSWeekCalendarUnit) fromDate:date];
	other = [cal dateFromComponents:components1];
	
	if(components.week == components1.week) {
		NSDateFormatter *formate = [[NSDateFormatter alloc] init];
		[formate setDateFormat:@"EEEE"];
		
		dateString = [formate stringFromDate:date];
		return dateString;
	}
	
	NSDateFormatter *formate = [[NSDateFormatter alloc] init];
	[formate setDateFormat:@"dd/MM/yyyy"];
	
	dateString = [formate stringFromDate:date];
	return dateString;
}

#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 _arrayDatas.count;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
	return 64;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *CellIdentifier = [NSString stringWithFormat:@"AllTableView%ld:%ld", (long)indexPath.section, (long)indexPath.row];
	
	UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
	if (cell == nil) {
		cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
	}
    
    // Configure the cell...
	NSMutableDictionary *dict = [_arrayDatas objectAtIndex:(_arrayDatas.count - indexPath.row - 1)];
	NSString *usersPhone = [[NSUserDefaults standardUserDefaults] objectForKey:USER_PREFIX];
	
	if ([[dict objectForKey:PARSE_CALL_STATUS] isEqualToString:@"Sent"] && [[dict objectForKey:LOC_PHONE] isEqualToString:usersPhone]) {
		// sent cell
		[[cell viewWithTag:0x100] removeFromSuperview];
		
		// location field
		cell.textLabel.text = [NSString stringWithFormat:@"To: %@", [dict objectForKey:LOC_TONAME]];
		cell.textLabel.textColor = [UIColor colorWithRed:54.0/255.0 green:225.0/255.0 blue:250.0/255.0 alpha:1.0];
		cell.textLabel.font = [UIFont boldSystemFontOfSize:15.0];
		
		// location name field
		cell.detailTextLabel.text = [dict objectForKey:LOC_NAME];
		cell.detailTextLabel.textColor = [UIColor lightGrayColor];
		
		// date field
		UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(176, 0, 96, 64)];
		NSString *string = [self dateStringFromToday:[dict objectForKey:LOC_TIME]];
		label.text = string;
		label.textColor = [UIColor lightGrayColor];
		label.font = [UIFont systemFontOfSize:15];
		label.textAlignment = NSTextAlignmentRight;
		[label setTag:0x100];
		[cell addSubview:label];
		
		cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
		
		
		
	} else if ([[dict objectForKey:PARSE_CALL_STATUS] isEqualToString:@"Sent"] && [[dict objectForKey:LOC_TOPHONE] isEqualToString:usersPhone]) {
		// receive cell
		[[cell viewWithTag:0x100] removeFromSuperview];
		
		// location field
		cell.textLabel.text = [NSString stringWithFormat:@"From: %@", [dict objectForKey:LOC_USER]];
		cell.textLabel.textColor = [UIColor colorWithRed:155.0/255.0 green:205.0/255.0 blue:67.0/255.0 alpha:1.0];
		cell.textLabel.font = [UIFont boldSystemFontOfSize:15.0];
		
		// location name field
		cell.detailTextLabel.text = [dict objectForKey:LOC_NAME];
		cell.detailTextLabel.textColor = [UIColor lightGrayColor];
		
		// date field
		UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(176, 0, 96, 64)];
		NSString *string = [self dateStringFromToday:[dict objectForKey:LOC_TIME]];
		label.text = string;
		label.textColor = [UIColor lightGrayColor];
		label.font = [UIFont systemFontOfSize:15];
		label.textAlignment = NSTextAlignmentRight;
		[label setTag:0x100];
		[cell addSubview:label];
		
		if ([[dict objectForKey:LOC_ISOPEN] boolValue]) {
			cell.accessoryView = nil;
			cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
		} else {
			UIImageView *imgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"mark_unread.png"]];
			[imgView setFrame:CGRectMake(0, 0, 10, 10)];
			cell.accessoryView = imgView;
		}
		
		
		
	} else if ([[dict objectForKey:PARSE_CALL_STATUS] isEqualToString:@"Request"]) {
		// request cell
		[[cell viewWithTag:0x100] removeFromSuperview];
		
		// location field
		cell.textLabel.text = [NSString stringWithFormat:@"From: %@", [self getNameFromPhoneInFriends:[dict objectForKey:LOC_USER]]];
		cell.textLabel.textColor = [UIColor colorWithRed:253.0/255.0 green:174.0/255.0 blue:55.0/255.0 alpha:1.0];
		cell.textLabel.font = [UIFont boldSystemFontOfSize:15.0];
		
		// location name field
		cell.detailTextLabel.text = @"";
		//cell.detailTextLabel.text = [dict objectForKey:LOC_NAME];
		//cell.detailTextLabel.textColor = [UIColor lightGrayColor];
		
		// date field
		UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(176, 0, 96, 64)];
		NSString *string = [self dateStringFromToday:[dict objectForKey:LOC_TIME]];
		label.text = string;
		label.textColor = [UIColor lightGrayColor];
		label.font = [UIFont systemFontOfSize:15];
		label.textAlignment = NSTextAlignmentRight;
		[label setTag:0x100];
		[cell addSubview:label];
		
		// is opened
		if ([[dict objectForKey:LOC_ISOPEN] boolValue]) {
			cell.accessoryView = nil;
			cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
		} else {
			UIImageView *imgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"mark_unread.png"]];
			[imgView setFrame:CGRectMake(0, 0, 10, 10)];
			cell.accessoryView = imgView;
		}
	}
	
	
    
    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
	//[self deselectRowAtIndexPath:indexPath animated:YES];
	NSMutableDictionary *dict = [_arrayDatas objectAtIndex:(_arrayDatas.count - indexPath.row - 1)];
	
	
	ShowWaitView1(YES, [self superview]);
	[self setUserInteractionEnabled:NO];
	
	
	// set mark to read to parse db
	NSString *usersPhone = [[NSUserDefaults standardUserDefaults] objectForKey:USER_PREFIX];
	
	
	if ([[dict objectForKey:PARSE_CALL_STATUS] isEqualToString:@"Sent"] && [[dict objectForKey:LOC_PHONE] isEqualToString:usersPhone]) {
		// sent cell
		
		UIImage *img = nil;
		if ([dict objectForKey:LOC_IMAGE]) {
			img = [UIImage imageWithData:[dict objectForKey:LOC_IMAGE]];
		}
		
		ShowWaitView1(NO, [self superview]);
		[self setUserInteractionEnabled:YES];
		
		NSMutableDictionary *info = [[NSMutableDictionary alloc] init];
		[info setObject:dict[LOC_TONAME] forKey:LOC_USER];
		[info setObject:dict[LOC_TOPHONE] forKey:LOC_PHONE];
		[info setObject:dict[LOC_NAME] forKey:LOC_NAME];
		[info setObject:dict[LOC_LAT] forKey:LOC_LAT];
		[info setObject:dict[LOC_LONG] forKey:LOC_LONG];
		[info setObject:dict[LOC_MSG] forKey:LOC_MSG];
		[info setObject:dict[LOC_BARPOS] forKey:LOC_BARPOS];
		
		//[info setObject:dict[LOC_TIME] forKey:LOC_TIME];
		NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
		[dateFormat setTimeZone:[NSTimeZone timeZoneWithName:@"CET"]];
		[dateFormat setDateFormat:@"yyyy-MM-dd HH:mm:ss zzz"];
			
		//object[PARSE_CALL_TIME] = [dateFormat stringFromDate:date];
		NSString *string = [dateFormat stringFromDate:dict[LOC_TIME]];
		[info setObject:string forKey:LOC_TIME];
		
		if (dict[LOC_TRACKING]) {
			[info setObject:dict[LOC_TRACKING] forKey:LOC_TRACKING];
		}
		
		if (dict[LOC_IMAGE]) {
			[info setObject:dict[LOC_IMAGE] forKey:LOC_IMAGE];
		}
		
		[self.historyDelegate openSentLocation:[[dict objectForKey:LOC_LAT] doubleValue] lng:[[dict objectForKey:LOC_LONG] doubleValue] msg:[dict objectForKey:LOC_MSG] barpos:[[dict objectForKey:LOC_BARPOS] floatValue] image:img info:info];
		
		
	} else if ([[dict objectForKey:PARSE_CALL_STATUS] isEqualToString:@"Sent"] && [[dict objectForKey:LOC_TOPHONE] isEqualToString:usersPhone]) {
		// received cell
		
		// query request table
		PFQuery *query = [PFQuery queryWithClassName:PARSE_TABLE_CALL];
		[query whereKey:PARSE_CALL_TO equalTo:usersPhone];
		[query whereKey:PARSE_CALL_STATUS equalTo:@"Sent"];
		[query whereKey:PARSE_CALL_MODIFIED equalTo:[dict objectForKey:LOC_TIME]];
		[query whereKey:PARSE_CALL_FROM equalTo:[dict objectForKey:LOC_PHONE]];
		[query whereKey:PARSE_CALL_ISOPEN equalTo:[dict objectForKey:LOC_ISOPEN]];
		
		//query.cachePolicy = kPFCachePolicyCacheThenNetwork;
		
		[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
			if (!error && objects.count == 1) {
				PFObject *obj = [objects firstObject];
				obj[PARSE_CALL_ISOPEN] = @YES;
				
				[obj saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
					NSDate *dbDate = (NSDate *)[obj updatedAt];
					[dict setObject:dbDate forKey:LOC_TRACKINGTIME];
					
					NSArray *array = [[NSArray alloc] initWithObjects:dict, nil];
					[self.historyDelegate replyLocationForRequest:array];
					
					ShowWaitView1(NO, [self superview]);
					[self setUserInteractionEnabled:YES];
				}];
				
			} else {
				NSLog(@"WARNING: Receive query failed");
				ShowWaitView1(NO, [self superview]);
				[self setUserInteractionEnabled:YES];
			}
		}];
		
		// set mark to read to local db
		[dict setObject:@YES forKey:LOC_ISOPEN];
		[_arrayDatas replaceObjectAtIndex:(_arrayDatas.count - indexPath.row - 1) withObject:dict];
		[self reloadData];

		
		
	} else if ([[dict objectForKey:PARSE_CALL_STATUS] isEqualToString:@"Request"]) {
		// request cell
		
		[dict setObject:[NSNumber numberWithBool:YES] forKey:LOC_ISOPEN];
		
		NSMutableDictionary *sentDict = [[NSMutableDictionary alloc] init];
		[sentDict setObject:dict[LOC_PHONE] forKey:LOC_PHONE];
		[sentDict setObject:[self getNameFromPhoneInFriends:[dict objectForKey:LOC_USER]] forKey:LOC_USER];
		
		//[self.historyDelegate replyLocationForRequest:array];
		[self.historyDelegate sendLocationForRequest:@[sentDict]];
		
		
		// save to parse opening information
		NSString *usersPhone = [[NSUserDefaults standardUserDefaults] objectForKey:USER_PREFIX];
		
		/*
		 NSString *strPre1 = [NSString stringWithFormat:@"%@ = '%@'", PARSE_CALL_TIME, dict[LOC_TIME]];
		 NSString *strPre2 = [NSString stringWithFormat:@"%@ = '%@'", PARSE_CALL_FROM, dict[LOC_USER]];
		 NSString *strPre3 = [NSString stringWithFormat:@"%@ = '%@'", PARSE_CALL_TO, usersPhone];
		 NSString *strPre4 = [NSString stringWithFormat:@"%@ = '%@'", PARSE_CALL_STATUS, @"Request"];
		 NSPredicate *predicate = [NSPredicate predicateWithFormat:strPre1, strPre2, strPre3, strPre4];
		 
		 PFQuery *query = [PFQuery queryWithClassName:PARSE_TABLE_CALL predicate:predicate];
		 */
		
		PFQuery *query = [PFQuery queryWithClassName:PARSE_TABLE_CALL];
		[query whereKey:PARSE_CALL_TO equalTo:usersPhone];
		[query whereKey:PARSE_CALL_STATUS equalTo:@"Request"];
		[query whereKey:PARSE_CALL_MODIFIED equalTo:[dict objectForKey:LOC_TIME]];
		[query whereKey:PARSE_CALL_FROM equalTo:[dict objectForKey:LOC_PHONE]];
		
		//query.cachePolicy = kPFCachePolicyCacheThenNetwork;
		
		[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
			if (!error) {
				for (PFObject *obj in objects) {
					obj[PARSE_CALL_ISOPEN] = @YES;
					[obj saveInBackground];
				}
				
				ShowWaitView1(NO, [self superview]);
				[self reloadData];
				
				[self setUserInteractionEnabled:YES];
				
			} else {
				NSLog(@"WARNING: Request query failed");
				
				ShowWaitView1(NO, [self superview]);
				[self reloadData];
				[self setUserInteractionEnabled:YES];
			}
		}];
		
		
		// save to local db
		[dict setObject:@YES forKey:LOC_ISOPEN];
		[_arrayDatas replaceObjectAtIndex:(_arrayDatas.count - indexPath.row - 1) withObject:dict];
		[self reloadData];
	}
}

@end
 
I’d try isolating the two major components (i.e., the iOS app vs the backend).

It would be reasonably easy to setup a test interface to test the response time from the Parse side (a Ruby or Python script, even JS in a browser).

I’m note sure the complexity of the backend, but if you became convinced it was Parse (and there wasn’t performance tuning options, or more resources to allocate), then you _could_ deploy the backend (even if it was a just a subset of the functionality) on another service to test against your iOS code.

It doesn’t sound like you need to get hands-on with the OS, I’d stick with some kind of cloud/PaaS option (which may be Parse if you determine it’s your implementation on the server or client side...)
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.