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.
Related
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];
I'm new to iOS development and in my app I'm seeing some strange memory usage behavior.
I'm getting objects from server in such setupDataForPage method:
- (void)setupDataForPage:(int)page actionType:(NSString *)type success:(void (^)())callback
{
__weak MyTableViewController *weakSelf = self;
// clearing image cache because feed contains a lot of images
[[SDImageCache sharedImageCache] clearMemory];
[[SDImageCache sharedImageCache] clearDisk];
MyHTTPClient *API = [MyHTTPClient new];
[API feedFor:page success:^(AFHTTPRequestOperation *operation, id data) {
NSArray *data = [data objectForKey:#"data"];
if ([data count] > 0) {
// remove all objects to refresh with new ones
if ([type isEqualToString:#"pullToRefresh"]) {
[weakSelf.models removeAllObjects];
}
// populate data
NSMutableArray *result = [NSMutableArray new];
for (NSDictionary *modelData in data) {
MyModel *model = [[MyModel alloc] initWithDictionary:modelData];
[result addObject:model];
}
[weakSelf.models addObjectsFromArray:result];
[weakSelf.tableView reloadData];
}
callback();
} failure:nil];
}
it is used in viewDidLoad while getting initial request and also for pull refresh and infinite scrolling:
- (void)viewDidLoad {
[super viewDidLoad];
__block int page = 1;
__weak MyTableViewController *weakSelf = self;
// initial load
[self setupDataForPage:page actionType:#"initial" success:^{ page += 1; }];
// pull to refresh
[self.tableView addPullToRefreshWithActionHandler:^{
[weakSelf setupDataForPage:1 actionType:#"pullToRefresh" success:^{
[weakSelf.tableView.pullToRefreshView stopAnimating];
}];
}];
// infinite scrolling
[self.tableView addInfiniteScrollingWithActionHandler:^{
[weakSelf setupItemsForPage:page actionType:#"infiniteScroll" success:^{
page += 1;
[weakSelf.tableView.infiniteScrollingView stopAnimating];
}];
}];
}
I noticed that even after pull to refresh action which returns the same data (and I'm just removing all models and add them once more) my app's memory usage grows from nearly 19mb to 24mb..
I would like someone more experienced to look at this piece of code to determine whether it contains some possible memory leaks.. Should I somehow delete NSMutableArray *result variable after assigning it to models array?
Thanks!
First of all, use #autoreleasepool here:
#autoreleasepool {
NSArray *data = [data objectForKey:#"data"];
if ([data count] > 0) {
// remove all objects to refresh with new ones
if ([type isEqualToString:#"pullToRefresh"]) {
[weakSelf.models removeAllObjects];
}
// populate data
NSMutableArray *result = [NSMutableArray new];
for (NSDictionary *modelData in data) {
MyModel *model = [[MyModel alloc] initWithDictionary:modelData];
[result addObject:model];
}
[weakSelf.models addObjectsFromArray:result];
[weakSelf.tableView reloadData];
}
}
#autoreleasepool allows you to release every object allocated in that scope IMMEDIATELY.
This is perfect situation where use it ;)
I'm running a Parse program which grabs the data and creates objects from it using 'findObjectsInBackgroundWithBlock'. Once that is complete I update self and then call '[self.tableView setNeedsDisplay]', but nothing changes on my display and no new items are shown. Am I doing something wrong? and how do I fix it?
-(void)pullDown{
NSLog(#"Began PullDown");
NSMutableArray *bugs = [NSMutableArray arrayWithObjects: nil];
//NSMutableArray *bugs = [NSMutableArray arrayWithObjects: nil];
NSLog(#"Journal POSTS");
PFQuery *queryJournal = [PFQuery queryWithClassName:#"Post"];
[queryJournal whereKey:#"user" equalTo:[PFUser currentUser]];
NSLog(#"WHEN ARE YOU CALLED?");
[queryJournal findObjectsInBackgroundWithBlock:^(NSArray *posts, NSError *error) {
if (!error) {
// The find succeeded.
//NSLog(#"Successfully retrieved %# Posts.", posts);
// Do something with the found objects
for (PFObject *object in posts) {
int rating = object[#"Rating"];
NSLog(#"RATING object: %#; int: %i", object[#"Rating"], rating);
MSJournalerDoc *post = [[MSJournalerDoc alloc] initWithTitle:object[#"Title"] rating:rating thumbImage:object[#"imageFile"] fullImage:object[#"imageFile"]];
[bugs addObject:post];
}
NSLog(#"HELL YA");
NSLog(#"THE LIST: %#", bugs);
self.bugs = bugs;
NSLog(#"END OF LOOOOOOOOOOOOOOOPS %lu", bugs.count);
[self.tableView setNeedsDisplay];
NSLog(#"MOAR");
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
if ([PFUser currentUser]) {
NSLog(#"CURRENT USER");
[self pullDown];
NSLog(#"POST CURRENT USER");
}
else{
[self createUser];
[self createBug];
}
self.navigationItem.leftBarButtonItem = self.editButtonItem;
UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(insertNewObject:)];
self.navigationItem.rightBarButtonItem = addButton;
//Change the Title
self.title = #"Posts";
self.navigationItem.leftBarButtonItem = self.editButtonItem;
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
target:self action:#selector(addTapped:)];
NSLog(#"Finished ViewDidLoad");
}
You have a couple of different issues.
First, calling setNeedsDisplay on a view causes it to be redrawn, but this isn't enough for a table view because none of its data has been updated. Instead, you need to call reloadData which will update the data and trigger a redraw automatically.
Secondly, you are trying to use images returned by parse, but parse never returns images (at least not directly). So, accessing object[#"imageFile"] is returning you a PFFile, not a UIImage. You need to call getDataInBackgroundWithBlock: to get the image data before you can use it.
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 :)
I am using SudzC to get webservices, that webservice give me data, I tried to save the data in a property, but when I use to fill a tableview the property don't have any data. I use the debugger to view the property.
This es my handler
- (void) ConsultarUnidadesOrganizacionalesPorEmpresaHandler: (id) value {
// Handle errors
if([value isKindOfClass:[NSError class]]) {
NSLog(#"%#", value);
return;
}
// Handle faults
if([value isKindOfClass:[SoapFault class]]) {
NSLog(#"%#", value);
return;
}
// Do something with the NSMutableArray* result
NSMutableArray *result = (NSMutableArray*)value;
NSMutableArray *unidadOrganizacional = [[NSMutableArray alloc] init];
self.myData = [NSMutableArray array];
for (int i = 0; i < [result count]; i++)
{
EWSUnidadNegocio *empresa = [[EWSUnidadNegocio alloc] init];
empresa = [result objectAtIndex:i];
[unidadOrganizacional addObject:[empresa Descripcion]];
}
self.myData = unidadOrganizacional;
}
And this is the part where I use the web service
- (void)viewDidLoad
{
// Do any additional setup after loading the view from its nib.
EWSEmpresaWebServiceSvc *service = [[EWSEmpresaWebServiceSvc alloc]init];
[service ConsultarUnidadesOrganizacionalesPorEmpresa:self action:#selector(ConsultarUnidadesOrganizacionalesPorEmpresaHandler:) EmpresaId:self.empresaID];
[super viewDidLoad];
}
And the tableview is empty. Why does this happen? How can I use the data and fill my tableview?
Try to change your code this way :
self.myData = [[NSMutableArray alloc] init]autorelease];
// your loop
[sel setMyData:unidadOrganizacional];
try loading it in a dictionary:
dict = [resp objectForKey:#"YourKey"];
if( ( dict == nil ) || ![dict isKindOfClass:[NSDictionary class]] ) {
NSLog( #"WARNING: %#", [dict description]);
return;
}
empID = [[dict objectForKey:#"empresaID"]copy];
NSLog(#"Your Value: %#", empID);
I found the answer, I just have to put
[_myTableView reloadData]
at the end of the method.