Determine Which Object Has Most of One String - ios

I use Parse.com and have a PFObject that I use to populate a TableView. The PFObject contains several NSStrings and one NSArray. The array will contain days of week, some of which occur multiple times. I just need a way to determine which object has the most of each day of the week in that Array. I have had some success with finding the most popular one, but it gives numbers for the title of array.
[super viewWillAppear:animated];
PFQuery *query = [self queryForTable];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
NSLog(#"this should be all of the objects %#", objects];
// now just run the code I suggest, adapting objects as the array of arrays
NSArray *maxOccurrenceArray = nil;
NSInteger maxOccurrences = -LONG_MAX;
for (PFObject *pfObject in objects) {
NSArray *array = [pfObject objectForKey:#"THE_NAME_OF_THE_ARRAY_PROPERTY"];
NSInteger occurrences = [self occurrencesOf:#"Sunday" inArray:array];
if (occurrences > maxOccurrences) {
maxOccurrences = occurrences;
maxOccurrenceArray = array;
}
}
NSLog(#"The array with the most occurrences is %#", maxOccurrenceArray);
}];
NSArray *maxOccurrenceArray = nil;
NSInteger maxOccurrences = -LONG_MAX;
for (NSArray *array in arrays) {
NSInteger occurrences = [self occurrencesOf:#"Sunday" inArray:array];
if (occurrences > maxOccurrences) {
maxOccurrences = occurrences;
maxOccurrenceArray = array;
}
}
NSLog(#"The array with the most occurrences is %#", maxOccurrenceArray);

Related

Search more than 1000 queries in parse iOS

I have a parse iOS app where I need to search the names of a couple thousand users (~3,000). I am trying to modify my search code so that I can do this but I need help. Right now my code for search looks like this:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (tableView == self.tableView) {
return self.objects.count;
} else {
return self.searchResults.count;
}
}
-(void)filterResults:(NSString *)searchTerm :(int)limit :(int)skip {
[self.searchResults removeAllObjects];
PFQuery *query = [PFQuery queryWithClassName:#"_User"];
[query whereKey:#"isTeacher" equalTo:#"False"];
[query setLimit: limit];
[query setSkip: skip];
[[[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (objects.count == limit) {
[self performTeacherQueryWithLimit:limit andSkip:skip+limit];
}
else{
NSArray *results = [NSArray arrayWithArray:objects];
NSLog(#"%#", results);
NSLog(#"%lu", (unsigned long)results.count);
NSLog(#"results^");
[self.searchResults addObjectsFromArray:results];
NSPredicate *searchPredicate =
[NSPredicate predicateWithFormat:#"SELF.name contains[c] %#",searchTerm];
_searchResults = [NSMutableArray arrayWithArray:[results filteredArrayUsingPredicate:searchPredicate]];
[self.searchDisplayController.searchResultsTableView reloadData];
NSLog(#"%#", _searchResults);
NSLog(#"%lu", (unsigned long)_searchResults.count);
NSLog(#"search results^");
}
}];
]]
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
[self filterResults:searchString];
return YES;
}
This code will not work because I call the filterResults at the bottom without all the correct parameters but that is because I got halfway through and now I am stuck. I know I need to use the setSkip but I'm not sure how to make that work for my searching. Any help would be awesome! Thanks!
I do this sort of thing with a method that handles the query and its results together, like this:
- (void)runQuery:(PFQuery *)query filling:(NSMutableArray *)array completion:(void (^)(BOOL))completion {
query.skip = array.count;
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
[array addObjectsFromArray:objects];
if (objects.count < query.limit) {
return completion(YES);
} else {
[self runQuery:query filling:array completion:completion];
}
} else {
return completion(NO);
}
}];
}
Use it like this:
PFQuery *query = [PFQuery queryWithClassName:#"MyClass"];
// setup query
query.limit = // set this to a reasonable size
// the given method will do ceil(N / limit) finds, where N is the number
// of rows that satisfy the query
NSMutableArray *array = [#[] mutableCopy];
[self runQuery:query filling:array completion:^(BOOL success) {
NSLog(#"%#", array);
// you would do your local search and set search results here
}];
A more functional version would call a progress block in between queries. This would allow you to continuously update results. For that, just add a progress block parameter and call it right after [array addObjectsFromArray:objects];.

How could this be possible? UITableView datasource Count Weird Behavior

I don't understand how this is possible or why this is happening. Can anyone give me an idea?
I added more code to help you figure it out, however, i'm not sure how the extra code will help.
NSMutableArray *messages = [[NSMutableArray alloc] init];
PFUser *currentUser = [PFUser currentUser];
PFQuery *query = [PFQuery queryWithClassName:#"message"];
[query whereKey:#"receiver" equalTo:currentUser.objectId];
[query orderByDescending:#"createdAt"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error && objects !=NULL) {
NSMutableArray *listOfLastMsgs = [[NSMutableArray alloc] init];
for (PFObject *object in objects) {
Boolean *tester = false;
for(int i = 0;i<listOfLastMsgs.count;i++){
if([[object objectForKey:#"sender"] isEqualToString:[[listOfLastMsgs objectAtIndex:i] objectForKey:#"sender"]]){
tester = true;
}
}
if(!tester){
[listOfLastMsgs addObject:object];
}
}
for(int i = 0;i<listOfLastMsgs.count;i++){
NSString *s = [[listOfLastMsgs objectAtIndex:i] objectForKey:#"message"];
if(s.length > 80){
s = [s substringToIndex:80];
}
[messages addObject:s];
}
NSLog(#"in did load %lu", (unsigned long)messages.count);
[self.tableView reloadData];
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
NSLog(#"in number of rows %lu", (unsigned long)messages.count);
return messages.count;
}
Here is my output log
2014-07-25 18:15:32.980 myapp[5696:60b] in number of rows 0
2014-07-25 18:15:35.990 myapp[5696:60b] in did load 2
2014-07-25 18:15:35.991 myapp[5696:60b] in number of rows 0
Assuming that big hunk of code is in your viewDidLoad the problem is simple - you have a local messages variable that you setup in viewDidLoad and your numberOfRowsInSection is referencing an uninitialized messages instance variable.
Assuming you really do have an ivar named messages, in viewDidLoad, change:
NSMutableArray *messages = [[NSMutableArray alloc] init];
to:
messages = [[NSMutableArray alloc] init];

New Data save to Mutable Array in Parse not calling save function

I have a module that saves data based on user inputs from text fields and adds it to an array saved in Parse. Testing with pre-populated data the module works fine. However, if I go to add data where there previously wasn't any it causes the app to ignore the saving element all together. What is the best way to add new arrays to Parse where no previous data existed? Here is the existing code:
- (IBAction)saveButton:(id)sender
{
[getData showGlobalProgressHUDWithTitle:#"Saving Test"];
PFQuery *tankQuery = [PFQuery queryWithClassName:#"WaterTests"];
[tankQuery whereKey:#"tankObjectId" equalTo:_passedValue];
[tankQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error)
{
for (PFObject *object in objects)
{
calciumArray = [object valueForKey:#"calciumArray"];
nitrateArray = [object valueForKey:#"nitrateArray"];
phosArray = [object valueForKey:#"phosphateArray"];
salinityArray = [object valueForKey:#"salinityArray"];
alkArray = [object valueForKey:#"alkArray"];
phArray = [object valueForKey:#"phArray"];
tempArray = [object valueForKey:#"tempArray"];
[calciumArray addObject: addCalcium.text];
[nitrateArray addObject: addNitrate.text];
[phosArray addObject: addPhosphate.text];
[salinityArray addObject: addSalinity.text];
[alkArray addObject: addAlk.text];
[phArray addObject: addPH.text];
[tempArray addObject: addTemp.text];
[object saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (!error)
{
NSLog(#"Something happened");
[getData dismissGlobalHUD];
[self hideTestView];
}
else
{
NSLog(#"Nothing happened: %#", error);
}
[self resignFirstResponder];
[_chartView reloadData];
}];
}
}
}];
}
I know that I'm close, but don't quite understand why it's not firing off the saving code. I believe its because I'm trying to retrieve objects that are empty first, but I could be wrong about that. Anyone have any advice for this?
UPDATE Here is the ViewDidLoad Code as it pertains to retrieving the data.
- (void)viewDidLoad
{
self.title = #"Water Quality";
statQuery = [PFQuery queryWithClassName:#"WaterTests"];
[statQuery whereKey:#"tankObjectId" equalTo:_passedValue];
[statQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error)
{
if (!error)
{
for (PFObject *object in objects)
{
[statQuery whereKey:#"tankObjectId" equalTo:_passedValue];
calciumArray = [object valueForKey:#"calciumArray"];
_footerView.sectionCount = calciumArray.count;
NSLog(#"CALCIUM ARRAY: %#", calciumArray);
nitrateArray = [object valueForKey:#"nitrateArray"];
NSLog(#"NITRATE ARRAY: %#", nitrateArray);
phosArray = [object valueForKey:#"phosphateArray"];
NSLog(#"PHOSPHATE ARRAY: %#", phosArray);
salinityArray = [object valueForKey:#"salinityArray"];
NSLog(#"SALINITY ARRAY: %#", salinityArray);
alkArray = [object valueForKey:#"alkArray"];
NSLog(#"ALKALINITY ARRAY: %#", alkArray);
phArray = [object valueForKey:#"phArray"];
NSLog(#"PH ARRAY: %#", phArray);
tempArray = [object valueForKey:#"tempArray"];
NSLog(#"TEMPERATURE ARRAY: %#", tempArray);
}
}
if (calciumArray == nil || [calciumArray count] == 0)
{
NSLog(#"You should probably fire off the new test function here.");
[_chartView setUserInteractionEnabled:NO];
[self newTest:self];
NSLog(#"Error: %#", error);
}
}];
This is the only other time the data is mentioned at all in the view. I allocate and initialize the arrays elsewhere, but I don't think that's the problem considering existing arrays pull and save just fine.
(PFObject *object in objects)
{
calciumArray = [object valueForKey:#"calciumArray"];
.
.
. //Other object for array
[arrayMu] [calciumArray addObject: addCalcium.text]; //Add in NSMutableArray
.
.
.
[objects save]; //Instead of saveinbackground.
}
Try this out. Also do reply back in time as after a long time I had would have to read all your query again as not in touch with it.
UPADTE...
-(IBAction)updateButton:(id)sender
{
PFQuery *query = [PFQuery queryWithClassName:#"UserDetail"];
NSString *str =self.nameTextField.text;
[query whereKey:#"name" containsString:str];
[query getFirstObjectInBackgroundWithBlock:^(PFObject *object, NSError *error)
{
if (!error)
{
NSLog(#"Successfully retrieved: %#", [object objectId]); //I retrieve the object succesfully
object[#"job"] = self.jobTextField.text; //Made changes to it.
object[#"hobby"] = self.hobbyTextField.text;
[object saveInBackground]; //Again saved it in background
}
else
{
NSLog(#"Error: %#", [error localizedDescription]);
} }];
}
Then I checked my parse db and my data was modified.
I was able to properly add a new array from a single object if nothing else was available by plainly adding a new object to Parse:
- (IBAction)saveButton:(id)sender
{
[getData showGlobalProgressHUDWithTitle:#"Saving Test"];
PFQuery *tankQuery = [PFQuery queryWithClassName:#"WaterTests"];
[tankQuery whereKey:#"tankObjectId" equalTo:_passedValue];
PFObject *testObject = [[PFObject alloc] initWithClassName:#"WaterTests"];
[tankQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (objects.count == 0)
{
[testObject setObject:_passedValue forKey:#"tankObjectId"];
[testObject addObject:addCalcium.text forKey:#"calciumArray"];
[testObject addObject:addNitrate.text forKey:#"nitrateArray"];
[testObject addObject:addPhosphate.text forKey:#"phosphateArray"];
[testObject addObject:addSalinity.text forKey:#"salinityArray"];
[testObject addObject:addAlk.text forKey:#"alkArray"];
[testObject addObject:addPH.text forKey:#"phArray"];
[testObject addObject:addTemp.text forKey:#"tempArray"];
[testObject saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (!error)
{
[getData dismissGlobalHUD];
[self hideTestView];
NSLog(#"Something, somewhere, saved.");
}
else
{
NSLog(#"HOORAY ERROR: %#", error);
}
[_chartView reloadData];
}];
}
However, I also had to check to see if there were any objects to begin with. If there were not any, simply add them in new. If there were, I had to run the code to query the database and add a for loop for every object that was found with the given criteria:
else if (objects.count != 0)
{
for (PFObject *object in objects)
{
[object addObject:addCalcium.text forKey:#"calciumArray"];
[object addObject:addNitrate.text forKey:#"nitrateArray"];
[object addObject:addPhosphate.text forKey:#"phosphateArray"];
[object addObject:addSalinity.text forKey:#"salinityArray"];
[object addObject:addAlk.text forKey:#"alkArray"];
[object addObject:addPH.text forKey:#"phArray"];
[object addObject:addTemp.text forKey:#"tempArray"];
[object saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error)
{
if (!error)
{
[getData dismissGlobalHUD];
[self hideTestView];
[_chartView reloadData];
NSLog(#"Here we go again");
}
}];
}
}
}];
}
I'm submitting this as my own answer and offering this to the community wiki to help others figure out similar problems. Problem: SOLVED!

Automatically refresh image using parse

I am showing an several images using an UIScrollView. however I would want it to refresh automatically.
I want to refresh it every time I show the view controller.
Using my code I have to push the refresh button every time which is just nonsense.
Here is the code : How can i do this ?
- (IBAction)refresh:(id)sender
{
NSLog(#"Showing Refresh HUD");
refreshHUD = [[MBProgressHUD alloc] initWithView:self.view];
[self.view addSubview:refreshHUD];
// Register for HUD callbacks so we can remove it from the window at the right time
refreshHUD.delegate = self;
// Show the HUD while the provided method executes in a new thread
[refreshHUD show:YES];
PFQuery *query = [PFQuery queryWithClassName:#"TPhoto"];
PFUser *user = [PFUser currentUser];
[query whereKey:#"user" equalTo:user];
[query orderByAscending:#"createdAt"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// The find succeeded.
if (refreshHUD) {
[refreshHUD hide:YES];
refreshHUD = [[MBProgressHUD alloc] initWithView:self.view];
[self.view addSubview:refreshHUD];
// The sample image is based on the work by http://www.pixelpressicons.com, http://creativecommons.org/licenses/by/2.5/ca/
// Make the customViews 37 by 37 pixels for best results (those are the bounds of the build-in progress indicators)
refreshHUD.customView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"37x-Checkmark.png"]];
// Set custom view mode
refreshHUD.mode = MBProgressHUDModeCustomView;
refreshHUD.delegate = self;
}
NSLog(#"Successfully retrieved %d photos.", objects.count);
// Retrieve existing objectIDs
NSMutableArray *oldCompareObjectIDArray = [NSMutableArray array];
for (UIView *view in [photoScrollView subviews]) {
if ([view isKindOfClass:[UIButton class]]) {
UIButton *eachButton = (UIButton *)view;
[oldCompareObjectIDArray addObject:[eachButton titleForState:UIControlStateReserved]];
}
}
NSMutableArray *oldCompareObjectIDArray2 = [NSMutableArray arrayWithArray:oldCompareObjectIDArray];
// If there are photos, we start extracting the data
// Save a list of object IDs while extracting this data
NSMutableArray *newObjectIDArray = [NSMutableArray array];
if (objects.count > 0) {
for (PFObject *eachObject in objects) {
[newObjectIDArray addObject:[eachObject objectId]];
}
}
// Compare the old and new object IDs
NSMutableArray *newCompareObjectIDArray = [NSMutableArray arrayWithArray:newObjectIDArray];
NSMutableArray *newCompareObjectIDArray2 = [NSMutableArray arrayWithArray:newObjectIDArray];
if (oldCompareObjectIDArray.count > 0) {
// New objects
[newCompareObjectIDArray removeObjectsInArray:oldCompareObjectIDArray];
// Remove old objects if you delete them using the web browser
[oldCompareObjectIDArray removeObjectsInArray:newCompareObjectIDArray2];
if (oldCompareObjectIDArray.count > 0) {
// Check the position in the objectIDArray and remove
NSMutableArray *listOfToRemove = [[NSMutableArray alloc] init];
for (NSString *objectID in oldCompareObjectIDArray){
int i = 0;
for (NSString *oldObjectID in oldCompareObjectIDArray2){
if ([objectID isEqualToString:oldObjectID]) {
// Make list of all that you want to remove and remove at the end
[listOfToRemove addObject:[NSNumber numberWithInt:i]];
}
i++;
}
}
// Remove from the back
NSSortDescriptor *highestToLowest = [NSSortDescriptor sortDescriptorWithKey:#"self" ascending:NO];
[listOfToRemove sortUsingDescriptors:[NSArray arrayWithObject:highestToLowest]];
for (NSNumber *index in listOfToRemove){
[allImages removeObjectAtIndex:[index intValue]];
}
}
}
// Add new objects
for (NSString *objectID in newCompareObjectIDArray){
for (PFObject *eachObject in objects){
if ([[eachObject objectId] isEqualToString:objectID]) {
NSMutableArray *selectedPhotoArray = [[NSMutableArray alloc] init];
[selectedPhotoArray addObject:eachObject];
if (selectedPhotoArray.count > 0) {
[allImages addObjectsFromArray:selectedPhotoArray];
}
}
}
}
// Remove and add from objects before this
[self setUpImages:allImages];
} else {
[refreshHUD hide:YES];
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
}
Call the refresh method from viewDidAppear in your view controller.
However, if that can happen often, you should consider keeping the images in a local cache and only refresh them if there is something new to show on the server.

Trouble accessing Mutable array

Im having trouble reassigning data in an array where I am trying to index user names. I am able to separate my original array into individual objects but am not able to send the value to a new array that I need to reference later on. The value and count for userNames in my self.userNamesArray = userNames; line is correct. But right after that when I log self.userNamesArray, I get (null). Any tips cause I'm not completely sure I'm cheers!
.h
#property (nonatomic, copy) NSMutableArray *userNamesArray;
.m
- (void)viewWillAppear:(BOOL)animated {
self.friendsRelation = [[PFUser currentUser] objectForKey:#"friendsRelation"];
PFQuery *query = [self.friendsRelation query];
[query orderByAscending:#"username"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error) {
NSLog(#"Error: %# %#", error, [error userInfo]);
}
else {
self.friends = objects;
NSArray *users = [self.friends valueForKey:#"username"];
NSLog(#"username:%#", users);
//Create an array of name wrappers and pass to the root view controller.
NSMutableArray *userNames = [[NSMutableArray alloc] initWithCapacity:[self.friends count]];
for (NSString *user in users) {
componentsSeparatedByCharactersInSet:charSet];
NSArray *nameComponents = [user componentsSeparatedByString:#" "];
UserNameWrapper *userNameWrapper = [[UserNameWrapper alloc] initWithUserName:nil nameComponents:nameComponents];
[userNames addObject:userNameWrapper];
}
self.userNamesArray = userNames;
NSLog(#"userNamesArray:%#",self.userNamesArray);
[self.tableView reloadData];
}
Here's the code where I need to reference the self.userNamesArray where again, it is comping up nil.
- (void)setUserNamesArray:(NSMutableArray *)newDataArray {
if (newDataArray != self.userNamesArray) {
self.userNamesArray = [newDataArray mutableCopy];
if (self.userNamesArray == nil) {
self.sectionsArray = nil;
NSLog(#"user names empty");
}
else {
[self configureSections];
}
}
}
Change your property method of mutable array to below:-
#property (nonatomic, retain)
NSMutableArray *userNamesArray;
Is this code calling itself recursively?
self.userNamesArray = [newDataArray mutableCopy];
is equivilent to:
[self setUserNamesArray: [newDataArray mutableCopy]];
If you need to override what happens during assignment, you can do as you're doing here but use _userNamesArray to reference the underlying member field.
First of all, I don't you need NSMutableArray for "userNamesArray". You could simply use NSArray. Now, try with below piece of code and you should be good to go:
self.userNamesArray = [NSMutableArray arrayWithArray:userNames];
You might get null because of this line:
NSArray *users = [self.friends valueForKey:#"username"];
Change it to:
NSArray *users = [self.friends objectForKey:#"username"];
In addition, follow #Abhinav suggestion to have more cleaner code :)

Resources