Xcode Parse cachePolicy seems to break my thread - xcode

so i'm fairly new to Xcode and C# so this may be a silly question, but none-the-less it has had me tearing my hair out for 3 days now.
Ok, so I am using Parse to fetch and save data, images, etc. I want to display a UITableView with the PFFile images. This bit I have managed.
The issue I have is the the scrolling performance is bad because i'm not caching the PFFile images that come in. I have no idea how to do this and any searches i make don't take into account using parse.
below is my code that puts the initial data into an array:
-(void) retrieveFromParse {
PFQuery *retrieveContent = [PFQuery queryWithClassName:#"NewsFeed"];
[retrieveContent orderByDescending:#"createdAt"];
//[retrieveContent unpinInBackground];
//retrieveContent.cachePolicy = kPFCachePolicyCacheElseNetwork;
[retrieveContent findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if(!error){
mainArray = [[NSArray alloc] initWithArray:objects];
}
[tableView reloadData];
}];
}
This code then gets the images:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"MyCell";
TableCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.profilePicture.layer.cornerRadius = cell.profilePicture.frame.size.height /1.99;
cell.profilePicture.layer.masksToBounds = YES;
cell.profilePicture.layer.borderWidth = 0;
PFObject *imageObject = [mainArray objectAtIndex:indexPath.row];
PFFile *imageFile = [imageObject objectForKey:#"image"];
[imageFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if(!error){
NSLog(#"%#",data);
cell.myImage.image = [UIImage imageWithData:data];
}
}];
return cell;
}
Now, you'll see i have commented out the cachePolicy because every time i use it, the thread breaks.
If someone could please alter my code or provide me with an example project using my code, to take into account caching either array and/or PFFile images, that would save me from going bald! :)
Many thanks in advance.

Did you tried retrieving the images in the viewdidload function instead of the cellForRowAtIndexPath?
I had the same problem before and I solved almost 90% of this problem by doing the following:
1- in the viewdidload, i wrote 2 queries: 1 for retrieving the data, and the other one to retrieve the images and store them in an array.
2- in the cellForRowAtIndexPath, i just added the images i got in the view did load to my cell.
this is what I did but unfortunately I'm still having a problem. The problem is that the images are not retrieved in the same order of retrieving the data "the image is not displayed next to the correct data :/".
I'm trying to solve this issue and if i did i will post the solution :)
Hope my Solution will help you. good luck ;)

Related

UIDocumentInteractionController broken in iOS 8

The related code below worked perfect when i was building for iOS 7, but it seems now in iOS 8, it's not working properly.
By properly, I mean in the sense where it's not actually sending the file or whatever to the chosen app.
Example: If I selected Mail, it would open the mail app with the image or zip I chose in the text field. Now it won't send and it takes forever to call/dismiss the UIDocumentInteractionController.
What am I doing wrong?
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self.tableView deselectRowAtIndexPath:indexPath animated:NO];
NSString *fileName = [directoryContents objectAtIndex:indexPath.row];
NSString *path;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
path = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"Downloads"];
path = [path stringByAppendingPathComponent:fileName];
documentController = [[UIDocumentInteractionController alloc] init];
documentController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:path]];
[documentController setDelegate:self];
[documentController presentOptionsMenuFromRect:CGRectZero inView:self.view animated:YES];
[documentController retain];
}
I have been playing around with the UIDocumentInteractionController and Delegate trying to fix a similar problem, the controller opened-up alright but selecting an application caused it to close without doing anything, my delegate method documentInteractionControllerDidDismissOpenInMenu also run alright afterwards.
In the console i got the notification enabledRemoteNotificationTypes is not supported in iOS 8.0 and later.
It turns out that this problem will accrue when one of these delegate methods is called :
documentInteractionControllerDidDismissOpenInMenu
documentInteractionControllerDidDismissOptionsMenu
(and possibly others, i did not check all of them)
I did not find any comment in the IOS Development Library or the UIDocumentInteractionController.h about these methods not supported for IOS 8.1 but at this point i cant find any other explanation.
Solution :
i replaced documentInteractionControllerDidDismissOpenInMenu
with didEndSendingToApplication
and it solved the problem for me.

save images to core data using magical record

I'm using magical record with Core Data.
In my app I have just one entity with some string attributes. Now, I would like to add an image to this entity, but I don't have any idea of how to do that using magical record. I searched but haven't found anything on the web. In my app all the data is inserted by the user, so also the image, by the camera or the photo library.
How do I store images using Magical Record and Core Data?
Just store the image in the documents folder of the app and save a string with the file url in the core data entity.
What you're trying above can be done easily. Best advice i can give you is make a new sample project just to save and retrieve image from the CoreData database. That way you know exactly how the process works. If you try to embed this functionality in your current project you might loose track of what happening where.
This is very quick example, i'll expect you to import the Delegates in your .h files yourself etc.
First initiate the UIImagePicker via button
-(IBAction)pickImage:(id)sender
{
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.delegate = self;
[self presentModalViewController:imagePicker animated:YES];
}
Once the image is selected, you can display it on the button using one of the delegate methods
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)selectedImage editingInfo:(NSDictionary *)editingInfo
self.imageButton.imageView.image = selectedImage;
To save it to CoreData assign your UIImage type to a Transformable type in your attribute in your database and then save the managedObjectContext
Links to help you:
UIImagePicker Class Reference
Magical Record Docs
CoreData Recipes Sample Project
Hope this help, good luck!
I found my answer:
to save:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString*nomeImmagine = [[NSString alloc] initWithFormat:#"%#", self.fieldName.text];
NSString *pngFilePath = [NSString stringWithFormat:#"%#/%#.png",documentsDirectory, nomeImmagine];
UIImage *image = self.showSelectedImage.image; // imageView is my image from camera
NSData *data1 = [NSData dataWithData:UIImagePNGRepresentation(image)];
[data1 writeToFile:pngFilePath atomically:NO];
to load:
-(void) loadImageFromPathInsideView
{
// [self loadImageFromPathInsideView];
Ricetta* contact =[[DataManager sharedClass]dammiTuttaLaRicetta:self.indice];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString*nomeImmagine = [[NSString alloc] initWithFormat:#"%#", contact.nome2];
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString* path = [NSString stringWithFormat:#"%#/%#.png",documentsDirectory, nomeImmagine];;
UIImage* image = [UIImage imageWithContentsOfFile:path];
self.image.image = image;
}
a word of advice. storing images as transformable (aka NSImage) type in core data is easy, but leads to overall slow app performance for even a low number (over 20) that range from 50k to 200kb with an average of 100k. even having those files linked via a relationship is slow, considering that one controller is often bound to another.
the above method of storing a local path name as a NSString pointing to Documents folder is heaps better for the overall experience.
that being said, creating a thumbnail image (of around 150x150) can be advantageous to create once and store that as a transient transformable NSImage, rather than loading the biggy and doing an on-the-fly resize a number of times. that performance can be observed easily scrolling up and down in a Table holding 50+ thumbnail images.

How do I get an edit button to work for a table view in xcode?

I've recently completed the apple tutorial on table views called Bird Watching and this worked fine. However, i'm now trying to take it further by adding an edit button and seem to be having a problem.
Below is the code that the MasterViewController uses to create my table. This works fine.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath (NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"BirdSightingCell";
static NSDateFormatter *formatter = nil;
if(formatter == nil){
formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterMediumStyle];
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
BirdSighting *sightingAtIndex = [self.dataController objectInListAtIndex:indexPath.row];
[[cell textLabel]setText:sightingAtIndex.name];
[[cell detailTextLabel]setText:[formatter stringFromDate:(NSDate *)sightingAtIndex.date]];
return cell;
}
I've tried using some of this code in order to get the edit button working and below is what I created. This doesn't work and I have no idea how to fix it.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
BirdSighting *sightingAtIndex = [self.dataController removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
} else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
}
}
One of the error messages I've had states "No visible #interface for BirdSightingDataController declares the selector removeObjectAtIndex.
I looked up the Bird Watching tutorial on the Apple website, to know exactly what you're talking about and which classes the objects are an instance of.
In your tableView:commitEditingStyle:forRowAtIndexPath: method, you try to remove a certain object. When removing an object, you have to make sure it's deleted from both your view (in this case your table view) and your model object (in this case your data controller). Your removed the row from your table view like this:
[tableView deleteRowsAtIndexPaths:#[indexPath]withRowAnimation:UITableViewRowAnimationFade];
This part looks good. However, you try to remove the object from your data controller using the following line of code:
BirdSighting *sightingAtIndex = [self.dataController removeObjectAtIndex:indexPath.row];
You sent the removeObjectAtIndex: method to self.dataController. The removeObjectAtIndex: method can only be sent to an instance of NSMutableArray. Your data controller is an instance of BirdSightingDataController, which is not an NSMutableArray. Thus, after trying to send the removeObjectAtIndex: method to self.dataController, you got an error.
To access the object at a certain index of your data controller array, you declared and implemented the objectInListAtIndex: method like this:
- (BirdSighting *)objectInListAtIndex:(NSUInteger)theIndex {
return [self.masterBirdSightingList objectAtIndex:theIndex];
}
Now you want to remove the object at a certain index of your data controller array, you could declare a method like removeObjectInListAtIndex: in your BirdSightingDataController header file as well. You can then implement it like this:
- (void)removeObjectInListAtIndex:(NSUInteger)theIndex {
[self.masterBirdSightingList removeObjectAtIndex:theIndex];
}
Note that this method doesn't return anything, as it just removes an object from the array. Make sure you use - (void) instead of - (BirdSighting *) in both your header and implementation file.
Now, instead of sending the removeObjectAtIndex: method to your data controller, you can simple remove the object (which the user deletes) from your data controller like this:
[self.dataController removeObjectInListAtIndex:indexPath.row];

How to load local images into UITableView without having impact on the scroll down performance?

Before somebody says something about this topic being duplicated several times, please note that I really don't need loading remote images from the web (SDWebImage github solution), I'm trying to load images dynamically saved on the documents folder, so they are local by the time I want to load them on my tableView having reference to them via a record on a sqlite table in which I saved the image name as it was generated by code.
So after parsing all my sqlite data, in my CellForRowAtIndexPath method at a certain point I have the following lines of code:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
...
NSString *imageName = [[favorites objectAtIndex:[indexPath row]] objectForKey:#"imagename"];
cell.image.image = [self loadImage: imageName]; // Is a custom cell so cell.image is a UIImageView, and I'm setting its image property
...
}
And my loadImage method looks like:
- (UIImage*)loadImage:(NSString*)imageName {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.png", imageName]];
return [UIImage imageWithContentsOfFile:fullPath];
}
Note also that this code actually works but scrolling down the table looks laggy. How can I improve the performance, I mean loading images in the background comes to my mind but the images are already there. Can someone give me a concrete solution on this please?
Just to let you know, I'm working with iOS 5 and ARC.
Any help would be very appreciated.
Firstly decrease the size of image you load.
Secondly try to use GCD to load image in tableView:cellForRowAtIndexPath:.

Adding annotation pin in mapview depending on cell chosen

I have Table View controller, then it has subclass DetailViewController, which content changes depending on cell chosen, but when move on, and from my DetailViewController go to MapView, I try to use same method I used to get text on DetailViewController, but it dont works, no matter what I do. Im stuck with it more like 3 week now:(
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (!self.detailViewController) {
self.detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
[self.navigationController pushViewController:self.detailViewController animated:YES];
[self.detailViewController changeProductText:[teksti objectAtIndex:indexPath.row]];
[self.detailViewController changeProductText1:[adrese objectAtIndex:indexPath.row]];
[self.detailViewController changeProductText2:[laimigastunda objectAtIndex:indexPath.row]];
[self.detailViewController changeImage:[imageChange objectAtIndex:indexPath.row]];
}
}
No matter what I change here, it dont work.
It looks from the code you are showing that you are not giving a data object to your detailViewController, but rather set directly the values.
This is not the way to do it and probably the reason why you are having issues. You need to grasp the concept of MVC and go back to it.
At least you should
1. build a dictionary in first view with keys #"teksti", #"adrese", #"longitude", #latitude".
2. Create a property in DetailViewController to hold the dictionary.
3. update the values displayed when displaying the DetailViewController
So that when you press the map button, you can then push a view containing a mapView and set the map to the latitude and longitude that you have.
So it would do:
NSDictionary *dict = [[NSDictionary alloc] initWithObjectsAndKeys:[teksti objectAtIndex:indexPath.row], #"teksti", [adrese objectAtIndex:indexPath.row], #"adrese", [latitude objectAtIndex:indexPath.row], #"latitude", [longitudes objectAtIndex:indexPath.row], #"longitude", nil];
[detailViewController setDict:dict];
and in the DetailViewController.m:
- (void)viewWillAppear:(BOOL)animated{
[self changeProductText:[dict objectForKey:#"teksti"]];
.... And so on
}
Your code will be useful to provide you with more details directions.

Resources