call NSString whit multiple parameters - ios

I am a beginner and maybe it is a trivial question.
I have this method:
-(NSString *)getInfoFormediaItem:(MPMediaItemCollection *)list {
NSString *trackCount;
if ([list count] > 0) {
trackCount = [NSString stringWithFormat:NSLocalizedString(#"%lu Songs", #""), (unsigned long)[list count]];
} else if([list count] == 1) {
trackCount = [NSString stringWithFormat:NSLocalizedString(#"1 Song", #"")];
} else {
trackCount = [NSString stringWithFormat:NSLocalizedString(#"0 Song", #"") ];
}
return [NSString stringWithFormat:#"%#", trackCount];
}
I would like to call it here with a MPMediaItemCollection:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if( cell == nil )
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"cell"];
}
MPMediaQuery *playlistsQuery = [MPMediaQuery playlistsQuery];
NSArray *playl = [playlistsQuery collections];
MPMediaItem *rowItem = [playl objectAtIndex:indexPath.row];
MPMediaItemCollection * collection = [[MPMediaItemCollection alloc] initWithItems:[NSArray arrayWithObject:rowItem]];
cell.detailTextLabel.text = [self getInfoFormediaItem:collection];
}
I would like to get the number of tracks in each playlist.
It doesn't work. How do I fix? Thanks in advance!

Why are you using performSelector:withObject:? Just call the method directly:
cell.detailTextLabel.text = [self getInfoFormediaItem:collection];
Why are you passing nil to the withObject: parameter? That's why your code goes to the else. list is nil so [list count] will always be 0. You need to pass an actual instance of a MPMediaItemCollection.
Why are you needlessly using stringWithFormat: for the 1 and 0 count checks? Just do:
-(NSString *)getInfoFormediaItem:(MPMediaItemCollection *)list {
NSString *trackCount;
if ([list count] > 1) {
trackCount = [NSString stringWithFormat:NSLocalizedString(#"%lu Songs", #""), (unsigned long)[list count]];
} else if([list count] == 1) {
trackCount = NSLocalizedString(#"1 Song", #"");
} else {
trackCount = NSLocalizedString(#"0 Song", #"");
}
return trackCount;
}
Based on your updated question, your cellForRowAtIndexPath code isn't correct for the getting the media collection. The collectionsmethod returns an array of MPMediaCollection objects, not MPMediaItem objects. You need:
MPMediaQuery *playlistsQuery = [MPMediaQuery playlistsQuery];
NSArray *playl = [playlistsQuery collections];
MPMediaItemCollection *collection = playl[indexPath.row];
Now you can use collection when you call getInfoFormediaItem:.

You simply don't need to call this statement:
cell.detailTextLabel.text = [self performSelector:#selector(getInfoFormediaItem:) withObject:nil];
in your "getInfoFormediaItem"method. You do that in your "cellforrowataIndexPath" method when you define the cell,just call like this:
cell.detailTextLabel.text = [self getInfoFormediaItem:This_Is_A_List_You_Wanna_Pass_To_The_Method];
and you should be good to go.

In addition to the problems pointed out by other posters, your if statement will not work as you want it to:
if ([list count] > 0) {
trackCount = [NSString stringWithFormat:NSLocalizedString(#"%lu Songs",
#""), (unsigned long)[list count]];
} else if([list count] == 1) {
trackCount = [NSString stringWithFormat:NSLocalizedString(#"1 Song", #"")];
} else {
trackCount = [NSString stringWithFormat:NSLocalizedString(#"0 Song", #"") ];
}
The "if ... >0" clause will match first, before checking for a value of 1, since 1 is > 0. Thus the "if ... == 1" will never evaluate as true. You need to reorder that if statement:
if ([list count] == 1) {
trackCount = NSLocalizedString(#"1 Song", #"");
else if ([list count] > 0) {
trackCount = [NSString stringWithFormat:NSLocalizedString(#"%lu Songs",
#""), (unsigned long)[list count]];
}
else
{
trackCount = NSLocalizedString(#"0 Songs", #"");
}

Related

Label is stop update when navigate to another viewcontroller

I am uploading file on server and showing percention on label,label is inside in the table cell, but when we navigate to another view ,its stop update, updated percentage is only show when we scroll table..
-(void)sendReplyOnServer:(NSMutableDictionary*)params
withMessage:(Message*)sendMessage
withIndex:(NSUInteger)deliveredIndex {
[self addReplyInDiscussion:sendMessage.disscussionId];
[[APIClient sharedClient] postReply:params andBlock:^(NSDictionary *responseDictionary,
NSError *error) {
#try {
[[DataManager sharedManager].sendMessages removeObject:sendMessage];
if (!error){
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary :[[responseDictionary objectForKey:#"response"] objectForKey:#"data"] ];
// [dict setObject:#"0" forKey:#"message_status"];
NSLog(#"%#",dict);
Message *deliveredMessage =
[Message modelObjectWithDictionary:dict];
if ([[responseDictionary objectForKey:#"response"] objectForKey:#"document"]){
Document *doc = [Document modelObjectWithDictionary:[[responseDictionary objectForKey:#"response"] objectForKey:#"document"]];
if ([DataManager sharedManager].documentListArray.count == 0){
[DataManager loadDocumentList];
}
if (![DataManager sharedManager].allDocumentsList){
[DataManager sharedManager].allDocumentsList = [[NSMutableArray alloc] init];
}
NSString *documentID = #"1";
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"documentId == %#",documentID];
NSArray *filteredArray = [[DataManager sharedManager].documentListArray filteredArrayUsingPredicate:predicate];
if (filteredArray.count != 0) {
Document *cameraRoll = [filteredArray objectAtIndex:0];
doc.parent = cameraRoll;
[cameraRoll.documents addObject:doc];
}
// Document *cameraRoll = [[DataManager sharedManager].documentListArray objectAtIndex:1];
// [cameraRoll.documents addObject:doc];
[[DataManager sharedManager].allDocumentsList addObject:doc];
[DataManager serializeDocumentList];
[DataManager serializeallDocumentList];
}
// if ([ deliveredMessage.deliveryStatus isEqualToString:#"1" ]) {
deliveredMessage.deliveryStatus = #"2";
//image save in file
// deliveredMessage.attachment.image = sendMessage.attachment.image;
if(sendMessage.attachment.image) {
deliveredMessage.attachment.image = sendMessage.attachment.image;
NSURL *url = [NSURL URLWithString:deliveredMessage.attachment.fileName];
NSString *name = [url lastPathComponent];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent:name];
// NSLog(#"my path == %#",path);
NSData * binaryImageData = UIImagePNGRepresentation(sendMessage.attachment.image);
[binaryImageData writeToFile:path atomically:YES];
}
// }
if ([sendMessage.disscussionId isEqualToString:disscussionId]) {
[self updateMessageList:deliveredMessage withIndex:deliveredIndex withSendMessage:sendMessage];
} else if ([disscussionId isEqualToString:#""] ) {
NSLog(#"reached in known");
NSString *string = [NSString stringWithFormat:#"dataIdentifier == %# ",sendMessage.disscussionId];
NSPredicate *predicate = [NSPredicate predicateWithFormat:string];
NSArray *filterArray = [[DataManager sharedManager].chatListArray filteredArrayUsingPredicate:predicate];
if (filterArray.count != 0 ) {
DiscussionData *discussionOject = [filterArray objectAtIndex:0];
NSUInteger indexOfManager = [[DataManager sharedManager].chatListArray indexOfObject:discussionOject];
DiscussionData *managerDiscussionOject = [[DataManager sharedManager].chatListArray objectAtIndex:indexOfManager];
string = [NSString stringWithFormat:#"identifier == \"%#\" ",deliveredMessage.identifier];
predicate = [NSPredicate predicateWithFormat:string];
filterArray = [managerDiscussionOject.replies.data filteredArrayUsingPredicate:predicate];
if ( filterArray.count != 0 ) {
NSMutableIndexSet *indexes = [[NSMutableIndexSet alloc] init];
NSUInteger idx = 0;
for ( Message *message in managerDiscussionOject.replies.data ) {
if ([message.identifier isEqualToString:deliveredMessage.identifier] && [message.identifier isEqualToString:message.internalBaseClassIdentifier]){
[indexes addIndex:idx];
}
idx ++;
}
[managerDiscussionOject.replies.data removeObjectsAtIndexes:indexes ];
[[NSNotificationCenter defaultCenter]
postNotificationName:UPDATE_REPLY_ARRAY
object:managerDiscussionOject];
}
//[DataManager serializeChatList];
}
//This case will be handle when time is same
}
else {
/* NSString *string = [NSString stringWithFormat:#"dataIdentifier == %# ",sendMessage.disscussionId];
NSPredicate *predicate = [NSPredicate predicateWithFormat:string];
NSArray *filterArray = [[DataManager sharedManager].chatListArray filteredArrayUsingPredicate:predicate];
if (filterArray.count != 0 ) {
DiscussionData *discussionOject = [filterArray objectAtIndex:0];
NSUInteger indexOfManager = [[DataManager sharedManager].chatListArray indexOfObject:discussionOject];
DiscussionData *managerDiscussionOject = [[DataManager sharedManager].chatListArray objectAtIndex:indexOfManager];
[DataManager serializeChatList];
}*/
}
}else {
NSLog(#"chat reply error === %#",error.localizedDescription);
sendMessage.deliveryStatus = #"3";
if ([sendMessage.disscussionId isEqualToString:disscussionId]) {
if ( repliesArray.count != 0 ) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[self indexOfReplyId:sendMessage.internalBaseClassIdentifier] inSection:0];
//NSIndexPath *indexPath = [NSIndexPath indexPathForRow inSection:0];
ChatDetailBaseTVC *cell = (ChatDetailBaseTVC *)[self.tableViewChatConv cellForRowAtIndexPath:indexPath];
cell.msgDeliveryStatusImageView.image = [UIImage imageNamed:MESSAGE_RETRY_IMAGE];
cell.status = #"3";
if (sendMessage.attachment) {
[cell.fileNameLabel setTitle:[NSString stringWithFormat:#" %#", cell.messageObj.attachment.title ] forState:UIControlStateNormal];
cell.progressValue = 0.0 ;
sendMessage.attachment.progress = #"0%";
}
[self updateContentInsetForTableView:self.tableViewChatConv animated:NO];
[self addReplyInDiscussion:sendMessage.disscussionId];
}
}
}
}#catch(NSException *e) {}
} showSpinner:YES showProgressView:^(float progress, NSString *messageId) {
[self updateCellProgress:progress :messageId :sendMessage];
}];
}
-(void)updateCellProgress:(float) progress :(NSString *)messageId :(Message*)sendMessage{
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[self indexOfReplyId:messageId] inSection:0];
ChatDetailAttached *cell = (ChatDetailAttached *)[self.tableViewChatConv cellForRowAtIndexPath:indexPath];
cell.messageObj.attachment.progress =[NSString stringWithFormat:#"%.0f%%",progress];
NSLog(#"indx %ld == message id %# progress == %#", (long)indexPath.row, messageId,cell.messageObj.attachment.progress);
if ([cell isKindOfClass:[ChatDetailAttached class]] &&
[sendMessage.internalBaseClassIdentifier isEqualToString:cell.messageObj.internalBaseClassIdentifier]) {
[cell.fileNameLabel setTitle:[NSString stringWithFormat:#" %# %#",cell.messageObj.attachment.progress, cell.messageObj.attachment.title ] forState:UIControlStateNormal];
}
}
put a NSTimer in viewDidLoad and set an action method on the selector of NSTimer:
And reload the tabel view in the action methode.g: [_mytableview reload];
Try to update the cell in main thread. And use block variable when you are using block.
Have a variable to hold the progress, CGFloat _progress, NSIndexPath *uploadIndex,
When upload is clicked save the index of cell to uploadIndex.
Update the progress variable
Reload the cell in showProgressView: block
showProgressView:^(float progress, NSString *messageId) {
dispatch_async(dispatch_get_main_queue(), ^{
_progress = progress; [self.tableViewChatConv reloadRowsAtIndexPaths:#[uploadIndex] withRowAnimation:UITableViewRowAnimationNone];
}
}
In cellForRowAtIndex , if([indexPath isEqual:uploadIndex]) then update the progress into cell, cell.progressValue = _progress ;

How to apply a logic in UISearchBar to reload a table with new data?

Hi guys I need your help in my situation, I am working with UISearchBar and all the delegate method I already declared, but I don't know the logic to reload the table data with filtered array.
All the data in my table come from json.
This is my code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
ChatListCell *cell=[tableView dequeueReusableCellWithIdentifier:#"contactListCell"];
if(!cell){
cell = [[ChatListCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"contactListCell"];
}
if (issearching) {
ChatListData *chatlistdata = [filteredContentList objectAtIndex:indexPath.row];
}
NSLog(#"ceel %#", cell);
ChatListData *chatlistData = [chatList objectAtIndex:indexPath.row];
NSString *txtName = chatlistData.name;
NSLog(#"name %#", txtName);
NSData *emojiData = [txtName dataUsingEncoding:NSUTF8StringEncoding];
NSString *emojiTxtName = [[NSString alloc] initWithData:emojiData encoding:NSNonLossyASCIIStringEncoding];
cell.txtName.text = emojiTxtName;
cell.txtTime.text = chatlistData.time;
NSString *stringImg = #"image";
NSString *stringVideo = #"video";
if(![chatlistData.mime_type isEqual: [NSNull null]]){
if ([chatlistData.mime_type rangeOfString:stringImg].location == NSNotFound || [chatlistData.mime_type rangeOfString:stringVideo].location == NSNotFound) {
if ([chatlistData.mime_type rangeOfString:stringImg].location == NSNotFound) {
cell.txtMsg.text = #"Image";
}else if([chatlistData.mime_type rangeOfString:stringVideo].location == NSNotFound){
cell.txtMsg.text = #"Video";
}
This is my tabview code of cell index.
-(void)searchBar:(UISearchBar*)searchBar textDidChange: (NSString*)text
{
if(text.length == 0)
{
issearching = FALSE;
}
else
{
NSMutableArray *chatlitdata;
issearching= true;
NSLog(#"searching");
filteredContentList = [[NSMutableArray alloc] init];
filteredContentList = chatlitdata;
// if(nameRange.location != NSNotFound || descriptionRange.location != NSNotFound)
{
[filteredContentList addObject:chatList];
}
}

iOS, UITableView flashing after i reload new data

Whats Happening
I have a UITableView, what i do is display the first ten records from the database then when the user scrolls to the end i retrieve just one record from the database and then add this to the array and reload the data but the UITableView seems to flash. I have added some code that will sync the data correctly so that when i scroll down and retrieve the record i don't get duplicate data.
Question
How can i stop the flashing or flickering when i add new data to the UITableView?
CODE
This is where i add the new data when i scroll down to the bottom:
-(void)renderScrollThreadInfo:(NSDictionary*)dic{
NSDictionary *thread = [dic objectForKey:#"thread"];
if((NSNull*)thread != [NSNull null]){
int t_ID;
int t_U_ID;
int t_C_ID;
NSString *t_Name;
NSString *t_Description;
NSDate *t_Created;
int t_Flagged;
int t_Rated;
NSString *firstName;
NSString *lastName;
NSString *categoryName;
for(NSDictionary *dict in thread)
{
if((NSNull *)[dict objectForKey:#"T_ID"] != [NSNull null]){
t_ID = [[dict objectForKey:#"T_ID"] intValue];
}
if((NSNull *)[dict objectForKey:#"T_U_ID"] != [NSNull null]){
t_U_ID = [[dict objectForKey:#"T_U_ID"] intValue];
}
if((NSNull *)[dict objectForKey:#"T_C_ID"] != [NSNull null]){
t_C_ID = [[dict objectForKey:#"T_C_ID"] intValue];
}
if((NSNull *)[dict objectForKey:#"T_Name"] != [NSNull null]){
t_Name = [dict objectForKey:#"T_Name"];
}
if((NSNull *)[dict objectForKey:#"T_Description"] != [NSNull null]){
t_Description = [dict objectForKey:#"T_Description"];
}
if((NSNull *)[dict objectForKey:#"T_Created"] != [NSNull null]){
NSString *timestampString = [dict objectForKey:#"T_Created"];
double timestampDate = [timestampString doubleValue];
t_Created = [NSDate dateWithTimeIntervalSince1970:timestampDate];
}
if((NSNull *)[dict objectForKey:#"T_Flagged"] != [NSNull null]){
t_Flagged = [[dict objectForKey:#"T_Flagged"] intValue];
}
if((NSNull *)[dict objectForKey:#"T_Rated"] != [NSNull null]){
t_Rated = [[dict objectForKey:#"T_Rated"] intValue];
}
if((NSNull *)[dict objectForKey:#"U_FirstName"] != [NSNull null]){
firstName = [dict objectForKey:#"U_FirstName"];
}
if((NSNull *)[dict objectForKey:#"U_LastName"] != [NSNull null]){
lastName = [dict objectForKey:#"U_LastName"];
}
if((NSNull *)[dict objectForKey:#"C_Name"] != [NSNull null]){
categoryName = [dict objectForKey:#"C_Name"];
}
ThreadInfo *threadObj = [ThreadInfo new];
threadObj.iD = t_ID;
threadObj.userId = t_U_ID;
threadObj.catId = t_C_ID;
threadObj.name = t_Name;
threadObj.description = t_Description;
threadObj.timeStampCreated = t_Created;
threadObj.flagged = t_Flagged;
threadObj.rated = t_Rated;
threadObj.firstName = firstName;
threadObj.lastName = lastName;
threadObj.category = categoryName;
BOOL foundThreadId = false;
for(int i = 0; i < [threadsArray count] - 1; i++){
ThreadInfo *tmpThreadInfo = (ThreadInfo*)[threadsArray objectAtIndex:i];
if(tmpThreadInfo.iD == t_ID){
foundThreadId = true;
}
}
if(!foundThreadId){
[threadsArray addObject:threadObj];
}
}
[tableViewThreads reloadData];
}
}
This is the code that calls a php script to get the next record:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if(tableViewThreads == tableView){
//NSLog(#"%d %d",[indexPath row], [threadsArray count] - 1);
if ([indexPath row] == [threadsArray count] - 2) {
ThreadInfo *threadInfo = (ThreadInfo*)[threadsArray objectAtIndex:[threadsArray count] - 1];
int tid = threadInfo.iD;
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 3) Load picker in background
dispatch_async(concurrentQueue, ^{
NSString *searchItem = textFieldSearchThreads.text;
NSString *myRequestString = [NSString stringWithFormat:#"Category=%d&TID=%d&SearchItem=%#",rowCategory, tid, searchItem];
NSString *response = [self setupPhpCall:myRequestString :#"getThread.php"];
dispatch_async(dispatch_get_main_queue(), ^{
if(response.length > 0){
[self renderScrollThreadInfo:[response JSONValue]];
}
});
});
}
}
if(tableViewPosts == tableView){
//NSLog(#"%d %d",[indexPath row], [threadsArray count] - 1);
if ([indexPath row] == [postsArray count] - 1) {
PostInfo *postInfo = (PostInfo*)[postsArray objectAtIndex:[postsArray count] - 1];
int pid = postInfo.iD;
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 3) Load picker in background
dispatch_async(concurrentQueue, ^{
NSString *myRequestString = [NSString stringWithFormat:#"TID=%d&PID=%d", chatThreadId, pid];
NSString *response = [self setupPhpCall:myRequestString :#"getStandalonePost.php"];
dispatch_async(dispatch_get_main_queue(), ^{
if(response.length > 0){
//[tableViewPosts scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:NO];
[self renderScrollPostInfo:[response JSONValue]];
}
});
});
}
}
}
This is the code where a set up my Custom Cells with data:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if(tableViewThreads == tableView){
NSString *cellIdentifier = #"cell";
ThreadTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
ThreadInfo *threadInfo = (ThreadInfo*)[self.threadsArray objectAtIndex:indexPath.row];;
if (cell == nil)
{
cell = [[ThreadTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
[cell setupView:threadInfo];
}
cell.labelFirstName.text = [NSString stringWithFormat:#"%# %#", threadInfo.firstName,threadInfo.lastName];
cell.labelTimestamp.text = [NSDateFormatter localizedStringFromDate:threadInfo.timeStampCreated dateStyle:NSDateFormatterMediumStyle timeStyle:NSDateFormatterMediumStyle];
cell.labelTimestamp.text = [cell.labelTimestamp.text stringByReplacingOccurrencesOfString:#"AM" withString:#""];
cell.labelTimestamp.text = [cell.labelTimestamp.text stringByReplacingOccurrencesOfString:#"PM" withString:#""];
cell.labelThreadName.text = threadInfo.name;
//cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
if(tableViewPosts == tableView){
NSString *cellIdentifier = #"cell2";
PostTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
PostInfo *postInfo = (PostInfo*)[self.postsArray objectAtIndex:indexPath.row];
if (cell == nil)
{
cell = [[PostTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
[cell setupView:postInfo];
}
cell.labelUserName.text = [NSString stringWithFormat:#"%# %# posted...", postInfo.firstName,postInfo.lastName];
cell.labelCreated.text = [NSDateFormatter localizedStringFromDate:postInfo.timeStampCreated dateStyle:NSDateFormatterMediumStyle timeStyle:NSDateFormatterMediumStyle];
cell.labelCreated.text = [cell.labelCreated.text stringByReplacingOccurrencesOfString:#"AM" withString:#""];
cell.labelCreated.text = [cell.labelCreated.text stringByReplacingOccurrencesOfString:#"PM" withString:#""];
cell.labelMessage.text = postInfo.message;
return cell;
//[cell.contentView addSubview:[self setupThreadItem:threadInfo]];
}
return nil;
}
Instead of calling [UITableView reloadData] when you receive new data, use [UITableView insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation

IndexPath.row changes when using search issue?

I am trying to successfully implement a UISearchcontroller into my UITableview however I have the following issues, I pass data using the indexPath.row method to the next view controller and the indexPath.row changes when I search, secondly I am using multiple arrays for my data in my tableview, and so what i've done is created another array that holds all of the other arrays content in one and searches through that, and it all works perfectly except when I want to pass my data because the indexPath.row changes instead of staying with the cell (which is what i need to happen). Please could you check out my code and see if you can help?
#import "AbsViewController.h"
#interface AbsViewController ()
#end
#implementation AbsViewController {
//these are all my arrays
//The arrays that carry for no equipment.
NSArray *tableData;
NSArray *thumbnails;
NSArray *sets;
NSArray *reps;
NSArray *instructions;
NSArray *materials;
NSArray *status;
NSArray *tips;
NSArray *difficulty;
NSArray *target;
//The arrays that carry for equipment.
NSArray *tableData1;
NSArray *thumbnails1;
NSArray *sets1;
NSArray *reps1;
NSArray *instructions1;
NSArray *materials1;
NSArray *status1;
NSArray *tips1;
NSArray *difficulty1;
NSArray *target1;
//The arrays that carry for bosu ball.
NSArray *tableData2;
NSArray *thumbnails2;
NSArray *sets2;
NSArray *reps2;
NSArray *instructions2;
NSArray *materials2;
NSArray *status2;
NSArray *tips2;
NSArray *difficulty2;
NSArray *target2;
//The arrays that carry for physio ball.
NSArray *tableData3;
NSArray *thumbnails3;
NSArray *sets3;
NSArray *reps3;
NSArray *instructions3;
NSArray *materials3;
NSArray *status3;
NSArray *tips3;
NSArray *difficulty3;
NSArray *target3;
//The arrays that carry for weighted.
NSArray *tableData4;
NSArray *thumbnails4;
NSArray *sets4;
NSArray *reps4;
NSArray *instructions4;
NSArray *materials4;
NSArray *status4;
NSArray *tips4;
NSArray *difficulty4;
NSArray *target4;
//Search array
NSArray *tableData5;
NSArray *status5;
NSArray *thumbnails5;
//The array for the search results.
NSArray *searchResults;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = #"Abdominal";
//Here im initializing my arrays.
// Find out the path of my array.
NSString *path = [[NSBundle mainBundle] pathForResource:#"Abs" ofType:#"plist"];
// Load the file content and read the data into arrays
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:path];
tableData = [dict objectForKey:#"name"];
thumbnails = [dict objectForKey:#"imageFile"];
status = [dict objectForKey:#"status"];
// Find out the path of recipes.plist
NSString *path1 = [[NSBundle mainBundle] pathForResource:#"Abs1" ofType:#"plist"];
// Load the file content and read the data into arrays
NSDictionary *dict1 = [[NSDictionary alloc] initWithContentsOfFile:path1];
tableData1 = [dict1 objectForKey:#"name"];
thumbnails1 = [dict1 objectForKey:#"imageFile"];
status1 = [dict1 objectForKey:#"status"];
// Find out the path of recipes.plist
NSString *path2 = [[NSBundle mainBundle] pathForResource:#"Abs2" ofType:#"plist"];
// Load the file content and read the data into arrays
NSDictionary *dict2 = [[NSDictionary alloc] initWithContentsOfFile:path2];
tableData2 = [dict2 objectForKey:#"name"];
thumbnails2 = [dict2 objectForKey:#"imageFile"];
status2 = [dict2 objectForKey:#"status"];
// Find out the path of recipes.plist
NSString *path3 = [[NSBundle mainBundle] pathForResource:#"Abs3" ofType:#"plist"];
// Load the file content and read the data into arrays
NSDictionary *dict3 = [[NSDictionary alloc] initWithContentsOfFile:path3];
tableData3 = [dict3 objectForKey:#"name"];
thumbnails3 = [dict3 objectForKey:#"imageFile"];
status3 = [dict3 objectForKey:#"status"];
NSString *path4 = [[NSBundle mainBundle] pathForResource:#"Abs4" ofType:#"plist"];
// Load the file content and read the data into arrays
NSDictionary *dict4 = [[NSDictionary alloc] initWithContentsOfFile:path4];
tableData4 = [dict4 objectForKey:#"name"];
thumbnails4 = [dict4 objectForKey:#"imageFile"];
status4 = [dict4 objectForKey:#"status"];
//this is the array that carries all the content.
NSString *path5 = [[NSBundle mainBundle] pathForResource:#"AbsTotal" ofType:#"plist"];
// Load the file content and read the data into arrays
NSDictionary *dict5 = [[NSDictionary alloc] initWithContentsOfFile:path5];
tableData5 = [dict5 objectForKey:#"name"];
status5 = [dict5 objectForKey:#"status"];
thumbnails5 = [dict5 objectForKey:#"thumbnails"];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
if (self.searchDisplayController.isActive) {
return 1;
}
return 5 ;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (tableView == self.searchDisplayController.searchResultsTableView) {
return [searchResults count];
}
else if (section == 0) {
return [tableData count];
}
else if (section == 1) {
return [tableData1 count];
}
else if (section == 2) {
return [tableData2 count];
}
else if (section == 3) {
return [tableData3 count];
}
else if (section == 4) {
return [tableData4 count];
}
else {
return [tableData5 count];
}
}
//this is my cellForRowAtIndexPath method.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"ExerciseCell";
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:simpleTableIdentifier];
}
if (tableView == self.searchDisplayController.searchResultsTableView) {
cell.textLabel.text = [searchResults objectAtIndex:indexPath.row];
}
else if (indexPath.section == 0) {
cell.textLabel.text = [tableData objectAtIndex:indexPath.row];
cell.detailTextLabel.text = [NSString stringWithFormat:#"Type: %#", [status objectAtIndex:indexPath.row]];
cell.imageView.image = [UIImage imageNamed:[thumbnails objectAtIndex:indexPath.row]];
}
else if (indexPath.section == 1) {
cell.textLabel.text = [tableData1 objectAtIndex:indexPath.row];
cell.detailTextLabel.text = [NSString stringWithFormat:#"Type: %#", [status1 objectAtIndex:indexPath.row]];
cell.imageView.image = [UIImage imageNamed:[thumbnails1 objectAtIndex:indexPath.row]];
}
else if (indexPath.section == 2) {
cell.textLabel.text = [tableData2 objectAtIndex:indexPath.row];
cell.detailTextLabel.text = [NSString stringWithFormat:#"Type: %#", [status2 objectAtIndex:indexPath.row]];
cell.imageView.image = [UIImage imageNamed:[thumbnails2 objectAtIndex:indexPath.row]];
}
else if (indexPath.section == 3) {
cell.textLabel.text = [tableData3 objectAtIndex:indexPath.row];
cell.detailTextLabel.text = [NSString stringWithFormat:#"Type: %#", [status3 objectAtIndex:indexPath.row]];
cell.imageView.image = [UIImage imageNamed:[thumbnails3 objectAtIndex:indexPath.row]];
}
else if (indexPath.section == 4) {
cell.textLabel.text = [tableData4 objectAtIndex:indexPath.row];
cell.detailTextLabel.text = [NSString stringWithFormat:#"Type: %#", [status4 objectAtIndex:indexPath.row]];
cell.imageView.image = [UIImage imageNamed:[thumbnails4 objectAtIndex:indexPath.row]];
}
else {
cell.textLabel.text = [tableData objectAtIndex:indexPath.row];
cell.detailTextLabel.text = [NSString stringWithFormat:#"Type: %#", [status objectAtIndex:indexPath.row]];
cell.imageView.image = [UIImage imageNamed:[thumbnails objectAtIndex:indexPath.row]];
}
return cell;
}
//this is where i've attempted to fix the issue but didn't work.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSInteger rowNumber = 0;
for (NSInteger i = 0; i < indexPath.section; i++) {
rowNumber += [self tableView:tableView numberOfRowsInSection:i];
}
rowNumber += indexPath.row;
NSLog(#"%ld",(long)rowNumber);
}
//this is where i filter my tableview
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"SELF contains[cd] %#", searchText];
searchResults = [tableData5 filteredArrayUsingPredicate:resultPredicate];
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller
shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString
scope:[[self.searchDisplayController.searchBar scopeButtonTitles]
objectAtIndex:[self.searchDisplayController.searchBar
selectedScopeButtonIndex]]];
return YES;
}
//Here i create my view for my header/
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
// create the parent view that will hold header Label
UIView* customView = [[UIView alloc] initWithFrame:CGRectMake(0,0,320,25)];
customView.backgroundColor = [UIColor belizeHoleColor];
UILabel *headerLabel = [[UILabel alloc] initWithFrame:CGRectZero];
headerLabel.backgroundColor = [UIColor belizeHoleColor];
headerLabel.font = [UIFont fontWithName:#"Avenir-Black" size:14];
headerLabel.frame = CGRectMake(6,0,320,25);
if (section == 1) {
headerLabel.text = #"";
}
if (section == 2) {
headerLabel.text = #"";
}
if (section == 3) {
headerLabel.text = #"";
}
if (section == 4) {
headerLabel.text = #"";
}
if (section == 0) {
headerLabel.text = #"";
}
headerLabel.textColor = [UIColor cloudsColor];
[customView addSubview:headerLabel];
return customView;
}
please if someone could help that would sooooooo appreciated.
thanks in advance.
//u can do this on - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath method first get
if (tableView == self.searchDisplayController.searchResultsTableView)
{
NSString *PassData = [tableData5 objectAtIndex:indexPath.row];
// NSString *passData = nil; //COMMENT THIS LINE SINCE IT CONTAINS SELECTED VALUE FROM SEARCH DISPLAY TABLEVIEW NO NEED TO BE ST NULL AGAIN "COMMENT THIS LINE AND TRY"
NSString *selectedStatus = nil;
UIImage *selectedThumbImage = nil;
//assuming ur array's contains equal number of objects
if([tableData containsObject:passData]) //if the search results contains an object in this array
{
//by using passData from search results tableview's tapped row u cn get all the below grouped tableview data now do for other array's
int index = [tableData indexOfObject:passData]; //get the index of selected array
selectedStatus = [status objectAtIndex:index]; //from that index get the status data
selectedThumbImage = [thumbnails objectAtIndex:index];//get thumbnil image from index
}
else if ([tableData1 containsObject:passData])
{
int index = [tableData1 indexOfObject:passData]; //get the index of selected array
selectedStatus = [status1 objectAtIndex:index]; //from that index get the status data
selectedThumbImage = [thumbnails1 objectAtIndex:index];//get thumbnil image from index
}
else if ([tableData2 containsObject:passData])
{
int index = [tableData2 indexOfObject:passData]; //get the index of selected array
selectedStatus = [status2 objectAtIndex:index]; //from that index get the status data
selectedThumbImage = [thumbnails2 objectAtIndex:index];//get thumbnil image from index
}
else if (//check for otehr remaining array)
{
//grab all details
}
//at the end your passData contains title , selectedStatus contains status , and selectedThumbImage contains thumb image use it to pass
}//end if (tableView == self.searchDisplayController.searchResultsTableView)

UITableView gets Slower with every new NSMutableArray

I have a UITableView that populates the results of a search that the user looks up. In order to do this I am using a NSMutableArray of Dictionaries where objects are added for the first 10, and then when the user scrolls to the bottom it populates the next 10 until there are no results left to show.
This all works well and good but I started to notice that the more searches that are done, the slower the table gets. Here is some of the code:
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
[self.objectsArray removeAllObjects];
[self.objectsArray setArray:nil];
[itemsTable reloadData];
[itemsTable scrollRectToVisible:CGRectMake(0, 0, 0, 0) animated:false];
[self loadItemsFromURL:searchURL withItemDescription:encodedString atStartRow:start andEndRow:end];
}
The above is when a new search is performed. It then does a NSURLConnection and responds with this:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
if (self.objectsArray == nil)
self.objectsArray = [NSMutableArray array];
// self.objectsArray = [[NSMutableArray alloc] init];
NSError *error;
NSDictionary *returnArray = [[NSJSONSerialization JSONObjectWithData:itemsData options:kNilOptions error:&error] valueForKey:#"items"];
for (id key in returnArray)
{
[self.objectsArray addObject:[returnArray objectForKey:key]];
}
counter += 10;
[itemsTable reloadData];
}
As you can see, if a user conducts a new search all objects are removed with [self.objectsArray removeAllObjects]and I even try to set the array to nil. If I perform multiple searches the UITableView gets slower and slower with scrolling each time. It is almost like the controller sees the array as getting larger and larger with each search even though I am removing all of the objects from it before the search. Any ideas or am I going about this the wrong way?
EDIT:
Here is the cellForRowAtIndexPath: method. cell is a subclassed UITableViewCell.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Product Cell";
static NSString *LoadCellIdentifier = #"Loading Cell";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if ([self.objectsArray count] <= 0 )
{
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.itemName.text = #"No items found.";
cell.itemPrice.text = #"";
cell.itemLocation.text = #"";
cell.addButton.hidden = YES;
}
else
{
if ([indexPath row] == [self.objectsArray count])
{
if ( [self.objectsArray count] >= 10 )
{
if ( [self.objectsArray count] < counter)
{
cell = [tableView dequeueReusableCellWithIdentifier:LoadCellIdentifier];
[cell.loadingSpinner stopAnimating];
cell.itemName.text = #"No more items found.";
}
else
{
if (!running)
{
[self loadItemsFromURL:searchURL withItemDescription:encodedString atStartRow:[self.objectsArray count] + 1 andEndRow:[self.objectsArray count] + 10];
cell = [tableView dequeueReusableCellWithIdentifier:LoadCellIdentifier];
cell.itemName.text = #"Loading more items...";
[cell.loadingSpinner startAnimating];
running = true;
}
else
{
cell = [tableView dequeueReusableCellWithIdentifier:LoadCellIdentifier];
[cell.loadingSpinner startAnimating];
}
}
}
}
else
{
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
NSArray *match = [self.objectsArray objectAtIndex:[indexPath row]];
cell.addButton.hidden = NO;
if ([match valueForKey:#"DESCRIPTION"] == [NSNull null] )
{
cell.itemName.text = #"Description not available.";
}
else
{
cell.itemName.text = [match valueForKey:#"DESCRIPTION"];
}
if ([match valueForKey:#"AD"] != [NSNull null])
{
NSMutableString *adString = [NSMutableString stringWithString:[match valueForKey:#"AD"]];
NSRange textRange;
textRange = [adString rangeOfString:#"1/"];
if (textRange.location != NSNotFound)
{
[adString replaceCharactersInRange:[adString rangeOfString:#"1/"] withString:#"$"];
}
else
{
[adString replaceCharactersInRange:[adString rangeOfString:#"/"] withString:#"/$"];
}
cell.itemPrice.text = adString;
}
else if ([match valueForKey:#"REGULAR"] == [NSNull null])
{
cell.itemPrice.text = #"$ N/A";
}
else
{
NSNumberFormatter *currencyStyle = [[NSNumberFormatter alloc] init];
[currencyStyle setFormatterBehavior:NSNumberFormatterBehavior10_4];
[currencyStyle setNumberStyle:NSNumberFormatterCurrencyStyle];
NSNumber *price = [NSNumber numberWithDouble:[[match valueForKey:#"REGULAR"] doubleValue]];
NSString *stringPrice = [currencyStyle stringFromNumber:price];
cell.itemPrice.text = [NSString stringWithFormat:#"%#", stringPrice];
}
if ([match valueForKey:#"AISLE"] == [NSNull null])
{
cell.itemLocation.text = #"Item location: N/A";
}
else
{
cell.itemLocation.text = [NSString stringWithFormat:#"Item Location: %#", [match valueForKey:#"AISLE"]];
}
match = nil;
}
}
return cell;
}
EDIT 2:
Here is a snippet of what the JSON looks like:
{
items = {
263149 = {
AD = "###";
AISLE = 6A;
DESCRIPTION = "Cinnamon Toasters";
R = 9;
REGULAR = "#.##";
};
26599 = {
AD = "####";
AISLE = 6A;
DESCRIPTION = "Quaker Life Cereal";
R = 2;
REGULAR = "#.##";
};
40517 = {
AD = "###";
AISLE = 6A;
DESCRIPTION = "Toasted Oats";
R = 1;
REGULAR = "#.##";
};
};
};
Ok, I think your problem is the excessive creation of Array objects. So do the following instead of you're array creation:
NSDictionary *returnArray = [[NSJSONSerialization JSONObjectWithData:itemsData options:kNilOptions error:&error] valueForKey:#"items"];
for (NSDictionary *dict in returnArray in returnArray)
{
[self.objectsArray addObject:dict];
}
counter += 10;
[itemsTable reloadData];
What you'll get as you see is an array of NSDictionary objects, your return array is already an NSDictionary of dictionary objects. Also, slight observation, where are you resetting your counter?
EDIT: creating the NSDictionary from NSData:
[NSJSONSerialization JSONObjectWithData:self.requestData options:NSJSONReadingMutableContainers | NSJSONReadingMutableLeaves error:&error]
The requestData is generated using these delegate methods:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSLog(#"In didReceiveResponse");
[self.requestData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSLog(#"In didReceiveData");
[self.requestData appendData:data];
}
I was able to find the issue in one line in the cellForRowAtIndexPath:. I commented out: cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; at the top and made sure it was only called once. I also did do a bit of cleanup as suggested by 8vius and now only once NSString is being allocated in that method call. Once I did these two things it was nice and responsive again without any stutters.

Resources