I use Parse.com for backend, I've two views : InboxView (where I receive images from friends), and ChatView.
When I send images, I send images with recipientIds of user (that can be multiple users) in "Messages" class (parse).
I receive images in my InboxView, I can see in cell for row the name of the friend that send images.
I would like that when I select a row (username who sends me image) that stores the PFUser objectId of the user who sends me the image, and not all of the recipientIds.
How can I make that ?
Here is my code :
Inbox.h :
#import <UIKit/UIKit.h>
#import <Parse/Parse.h>
#import <MediaPlayer/MediaPlayer.h>
#interface InboxViewController : UITableViewController
#property (nonatomic, strong) NSArray *messages;
#property (nonatomic, strong) PFObject *selectedMessage;
#property (nonatomic, strong) MPMoviePlayerController *moviePlayer;
#property (nonatomic, strong) UIImage *MindleNav;
- (UIImage *)resizeImage:(UIImage *)image toWidth:(float)width andHeight:(float)height;
#end
and inbox.m :
#import "InboxViewController.h"
#import "ImageViewController.h"
#import <AVFoundation/AVFoundation.h>
#import "LoginViewController.h"
#import "FriendsViewController.h"
#interface InboxViewController ()
#end
#implementation InboxViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.MindleNav = [UIImage imageNamed:#"MindleNavItem.png"];
UIImage *newImage = [self resizeImage:self.MindleNav toWidth:150.0f andHeight:48.0f];
self.navigationItem.titleView = [[UIImageView alloc] initWithImage:newImage];
self.MindleNav = newImage;
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
PFQuery *query = [PFQuery queryWithClassName:#"Messages"];
[query whereKey:#"recipientIds" equalTo:[[PFUser currentUser] objectId]];
[query orderByDescending:#"createdAt"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error) {
NSLog(#"Error: %# %#", error, [error userInfo]);
}
else {
// We found messages!
self.messages = objects;
[self.tableView reloadData];
}
}];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.messages count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
PFObject *message = [self.messages objectAtIndex:indexPath.row];
cell.textLabel.text = [message objectForKey:#"senderName"];
NSString *fileType = [message objectForKey:#"fileType"];
if ([fileType isEqualToString:#"image"]) {
cell.imageView.image = [UIImage imageNamed:#"icon_image"];
}
else {
// cell.imageView.image = [UIImage imageNamed:#"icon_video"];
}
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.selectedMessage = [self.messages objectAtIndex:indexPath.row];
NSString *fileType = [self.selectedMessage objectForKey:#"fileType"];
if ([fileType isEqualToString:#"image"]) {
[self performSegueWithIdentifier:#"showImage" sender:self];
}
else {
// File type is text
// // File type is video
// PFFile *videoFile = [self.selectedMessage objectForKey:#"file"];
// NSURL *fileUrl = [NSURL URLWithString:videoFile.url];
// self.moviePlayer.contentURL = fileUrl;
// [self.moviePlayer prepareToPlay];
// UIImage *thumbnail = [self thumbnailFromVideoAtURL:self.moviePlayer.contentURL];
//
//// [self.moviePlayer thumbnailImageAtTime:0 timeOption:MPMovieTimeOptionNearestKeyFrame];
//
// // Add it to the view controller so we can see it
// UIImageView *imageView = [[UIImageView alloc] initWithImage:thumbnail];
// [self.moviePlayer.backgroundView addSubview:imageView];
// [self.moviePlayer setFullscreen:YES animated:YES];
}
// Delete it!
NSMutableArray *recipientIds = [NSMutableArray arrayWithArray:[self.selectedMessage objectForKey:#"recipientIds"]];
NSLog(#"Recipients: %#", recipientIds);
if ([recipientIds count] == 1) {
// Last recipient - delete!
// [self.selectedMessage deleteInBackground];
}
else {
// Remove the recipient and save
// [recipientIds removeObject:[[PFUser currentUser] objectId]];
// [self.selectedMessage setObject:recipientIds forKey:#"recipientIds"];
// [self.selectedMessage saveInBackground];
}
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showImage"]) {
[segue.destinationViewController setHidesBottomBarWhenPushed:YES];
ImageViewController *imageViewController =
(ImageViewController *)segue.destinationViewController;
imageViewController.message = self.selectedMessage;
}
}
- (UIImage *)thumbnailFromVideoAtURL:(NSURL *)url
{
AVAsset *asset = [AVAsset assetWithURL:url];
// Get thumbnail at the very start of the video
CMTime thumbnailTime = [asset duration];
thumbnailTime.value = 0;
// Get image from the video at the given time
AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
CGImageRef imageRef = [imageGenerator copyCGImageAtTime:thumbnailTime actualTime:NULL error:NULL];
UIImage *thumbnail = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
return thumbnail;
}
- (UIImage *)resizeImage:(UIImage *)truckImage toWidth:(float)width andHeight:(float)height {
CGSize newSize = CGSizeMake(width, height);
CGRect newRectangle = CGRectMake(0, 0, width, height);
UIGraphicsBeginImageContext(newSize);
[self.MindleNav drawInRect:newRectangle];
UIImage *resizedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return resizedImage;
}
#end
Related
How can I import all the contacts from the phone book in your application. and so that we could gain the imported contacts.
Andrei brother if you have not got answer still,I give you answer.I tried and got the solution.It works fine.
The AddressBookUI framework is deprecated in iOS 9, so we need to use Contact Framework.
First I set or hook up the tableView using XIB or Storyboard for showing contacts.
Must import the Contacts framework
ViewController.h
#import <UIKit/UIKit.h>
#import <Contacts/Contacts.h>
#interface ViewController : UIViewController<UITableViewDataSource,UITableViewDelegate>
{
}
#property (strong, nonatomic) IBOutlet UITableView *tableViewShowContacts;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
{
NSMutableArray *arrayContacts;
}
#end
#implementation ViewController
#synthesize tableViewShowContacts;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
arrayContacts = [[NSMutableArray alloc]init];
[self getAuthorizationandContact];
//Register the cell
[tableViewContactData registerClass:[UITableViewCell class] forCellReuseIdentifier:#"cell"];
[self.view addSubview:tableViewShowContacts];
}
-(void)fetchContactsandAuthorization
{
// Request authorization to Contacts
CNContactStore *store = [[CNContactStore alloc] init];
[store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (granted == YES)
{
//keys with fetching properties
NSArray *keys = #[CNContactFamilyNameKey, CNContactGivenNameKey, CNContactPhoneNumbersKey, CNContactImageDataKey];
NSString *containerId = store.defaultContainerIdentifier;
NSPredicate *predicate = [CNContact predicateForContactsInContainerWithIdentifier:containerId];
NSError *error;
NSArray *cnContacts = [store unifiedContactsMatchingPredicate:predicate keysToFetch:keys error:&error];
if (error) {
NSLog(#"error fetching contacts %#", error);
} else {
NSString *phone;
NSString *fullName;
NSString *firstName;
NSString *lastName;
UIImage *profileImage;
NSMutableArray *contactNumbersArray = [[NSMutableArray alloc]init];
for (CNContact *contact in cnContacts)
{
// copy data to my custom Contacts class.
firstName = contact.givenName;
lastName = contact.familyName;
if (lastName == nil) {
fullName=[NSString stringWithFormat:#"%#",firstName];
}else if (firstName == nil){
fullName=[NSString stringWithFormat:#"%#",lastName];
}
else{
fullName=[NSString stringWithFormat:#"%# %#",firstName,lastName];
}
UIImage *image = [UIImage imageWithData:contact.imageData];
if (image != nil) {
profileImage = image;
}else{
profileImage = [UIImage imageNamed:#"person-icon.png"];
}
for (CNLabeledValue *label in contact.phoneNumbers)
{
phone = [label.value stringValue];
if ([phone length] > 0) {
[contactNumbersArray addObject:phone];
}
}
NSDictionary* personDict = [[NSDictionary alloc] initWithObjectsAndKeys: fullName,#"fullName",profileImage,#"userImage",phone,#"PhoneNumbers", nil];
[arrayContacts addObject:[NSString stringWithFormat:#"%#",[personDict objectForKey:#"fullName"]]];
NSLog(#"The contacts are - %#",arrayContacts);
}
dispatch_async(dispatch_get_main_queue(), ^{
[tableViewShowContacts reloadData];
});
}
}
}];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - UITableView Data Source Methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return arrayContacts.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *strCell = #"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:strCell];
if(cell==nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:strCell];
}
cell.textLabel.text = arrayContacts[indexPath.row];
return cell;
}
The printed results of Contacts are
The contacts are - (
"John Appleseed",
"Kate Bell",
"Anna Haro",
"Daniel Higgins",
"David Taylor",
"Hank Zakroff"
)
I am getting a Thread 1, EXC: BAD ACCESS error on my [self.tableView registerNib:nib forCellReuseIdentifier:#"InboxCell"]; line. Everything was working fine but then I tried to bring in a BackroundView swift file, which was more of a headache then it was worth.
I deleted the BackgroundView swift file and cleaned it but now I have an error I cant figure out. I have a InboxCell.xib custom cell. Please hold my hand through it. Any help would be much appreciated! Here is my code:
//InboxTableViewController.h
#import "InboxCell.h"
#interface InboxTableViewController : UITableViewController
//this is property for the data source
#property (nonatomic, strong) NSArray *messages;
//something for showing image
#property (nonatomic, strong) PFObject *selectedMessage;
//for showing video
#property (nonatomic, strong) MPMoviePlayerController *moviePlayer;
- (IBAction)logout:(id)sender;
//set thumbnail
#property (nonatomic, strong) UIImage *thumbnail;
-(void)setThumbnailFromImage:(UIImage *)image;
#end
//.m
#interface InboxTableViewController ()
#end
#implementation InboxTableViewController
-(void)loadView
{
}
- (void)viewDidLoad {
[super viewDidLoad];
//THIS IS CUSTOM CELL!!!!!!!
UINib *nib = [UINib nibWithNibName:#"InboxCell" bundle:nil];
//register this nib to contain cell
/*THIS IS EXC ERROR*/
[self.tableView registerNib:nib forCellReuseIdentifier:#"InboxCell"];
//video alloc here so its reused for every video in inbox.
self.moviePlayer = [[MPMoviePlayerController alloc] init];
//Determining if a current user is logged in
PFUser *currentUser = [PFUser currentUser];
if (currentUser) {
NSLog(#"%#", currentUser.username);
} else {
[self performSegueWithIdentifier:#"showLogin" sender: self];
}
}
//// In case it hasnt been logged in after a while
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
//return nav and controller bar
[self.navigationController.navigationBar setHidden:NO];
[self.tabBarController.tabBar setHidden:NO];
PFQuery *query = [PFQuery queryWithClassName:#"Messages"];
// prevents error when running for first time in a while
if ([[PFUser currentUser] objectId] == nil) {
NSLog(#"No objectID");
} else {
[query whereKey:#"recipientIds" equalTo:[[PFUser currentUser] objectId]];
[query orderByDescending:#"createdAt"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error) {
NSLog(#"error %# %#", error, [error userInfo]);
} else {
self.messages = objects;
[self.tableView reloadData];
NSLog(#"Got %lu messages", (unsigned long)[self.messages count]);
}
}];
}
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showLogin"]) {
[segue.destinationViewController setHidesBottomBarWhenPushed:YES];
}
else if ([segue.identifier isEqualToString:#"showImage"]) {
//setting it so image tab wont pop up
[segue.destinationViewController setHidesBottomBarWhenPushed:YES];
ImageViewController *imageViewController = (ImageViewController *)segue.destinationViewController;
imageViewController.message = self.selectedMessage;
}
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.selectedMessage = [self.messages objectAtIndex:indexPath.row];
NSString *fileType = [self.selectedMessage objectForKey:#"fileType"];
if ([fileType isEqualToString:#"image"]) { //if image file
[self performSegueWithIdentifier:#"showImage" sender:self];
}
else {
//file type is video
PFFile *videoFile = [self.selectedMessage objectForKey:#"file"]; //getting the file
//now getting the URL property which is a string
NSURL *fileUrl = [NSURL URLWithString:videoFile.url];
//set the url for the movie player
self.moviePlayer.contentURL = fileUrl;
//prepare for file
[self.moviePlayer prepareToPlay];
//this is a quick thumbnail while it loads
// [[self.moviePlayer ]; NOT WORKING HERE
//Add video to view controller so you can see it
[self.view addSubview:self.moviePlayer.view];
//setting it to screen size CAN SET TO ANYSIZE!!!!!!!
[self.moviePlayer setFullscreen:YES animated:YES];
}
/* //this portion is to delete it after its viewed
NSMutableArray *recipientIds = [NSMutableArray arrayWithArray:[self.selectedMessage objectForKey:#"recipientIds"]];
//this is for each one individually
if ([recipientIds count] == 1) {
//last recipient delete
[self.selectedMessage deleteInBackground];
}
else {
//remove the recipients and save it
[recipientIds removeObject:[[PFUser currentUser] objectId]];
//now you have to update recipients array with new data
[self.selectedMessage setObject:recipientIds forKey:#"recipientIds"];
[self.selectedMessage saveInBackground];
} */
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// always use the count of data source
return [self.messages count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
/*CUSTOM CELL CODE */
InboxCell *cell = [tableView dequeueReusableCellWithIdentifier:#"InboxCell" forIndexPath:indexPath];
PFObject *message = [self.messages objectAtIndex:indexPath.row];
cell.titleLabel.text = [message objectForKey:#"senderName"];
//Date
NSDate *updated = [message updatedAt];
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"EEE, MMM d, h:mm a"];
cell.createdAtLabel.text = [NSString stringWithFormat:#"Filmed At: %#", [dateFormat stringFromDate:updated]];
// customizing the image next to the message to determine whether its a video or image.
NSString *fileType = [message objectForKey:#"file_type"];
if ([fileType isEqualToString:#"image"]) { // must add icons
cell.thumbnailView.image = [UIImage imageNamed: #"icon_image.png"];
// cell.imageView.image is the way to have a picture in a cell.
}
else {
cell.thumbnailView.image = [UIImage imageNamed:#"icon_video"];
}
return cell;
}
//this is used as a thumbnail before video plays
//- (UIImage *)thumbnailFromVideoAtURL:(NSURL *)url
//{
// AVAsset *asset = [AVAsset assetWithURL:url];
//
// // Get thumbnail at the very start of the video
// CMTime thumbnailTime = [asset duration];
// thumbnailTime.value = 0;
//
// // Get image from the video at the given time
// AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
//
// CGImageRef imageRef = [imageGenerator copyCGImageAtTime:thumbnailTime actualTime:NULL error:NULL];
// UIImage *thumbnail = [UIImage imageWithCGImage:imageRef];
// CGImageRelease(imageRef);
//
// return thumbnail;
//}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == 0) {
return 100;
}
else {
return 100;
}
}
- (IBAction)logout:(id)sender {
[PFUser logOut];
[self performSegueWithIdentifier:#"showLogin" sender:self];
}
- (IBAction)refresh:(id)sender {
[self.tableView reloadData];
[sender endRefreshing];
}
//setting thumbnail for cell
-(void)setThumbnailFromImage:(UIImage *)image
{
CGSize origImageSize = image.size;
CGRect newRect = CGRectMake(0, 0, 104, 76);
float ratio = MAX(newRect.size.width / origImageSize.width, newRect.size.height / origImageSize.height);
UIGraphicsBeginImageContextWithOptions(newRect.size, NO, 0.0);
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:newRect cornerRadius:5.0];
[path addClip];
CGRect projectRect;
projectRect.size.width = ratio * origImageSize.width;
projectRect.size.height = ratio * origImageSize.height;
projectRect.origin.x = (newRect.size.width - projectRect.size.width) / 2.0;
projectRect.origin.y = (newRect.size.height - projectRect.size.height) / 2.0;
[image drawInRect:projectRect];
UIImage *smallImage = UIGraphicsGetImageFromCurrentImageContext();
self.thumbnail = smallImage;
UIGraphicsEndImageContext();
}
#end
Your issue is being caused by the empty loadView method. Never leave that method empty. Either remove the method or give it a proper implementation of creating the view controller's main view and setting self.view.
Has anybody experienced cloud storage issues when building to your device using Xcode 7? Interfacing with AWSS3 buckets works fine from my simulator, but doesn't actually work after building to my phone using Xcode 7 beta. It doesn't crash or anything, I just can't load data into my S3 bucket.
CODE BELOW. Feel free to just pick a single implementation (say, delete) and test it out. I have a free developer account and am only using Xcode 7 to build on my device.
viewController.h
#import <UIKit/UIKit.h>
#import <AWSS3/AWSS3.h>
#interface tableTableViewController : UIViewController <UIImagePickerControllerDelegate, UINavigationControllerDelegate, UITableViewDelegate>
#property (weak, nonatomic) IBOutlet UIImageView *image;
- (IBAction)cameraRoll:(id)sender;
- (IBAction)editButton:(id)sender;
#property (strong, nonatomic) NSMutableArray *imageNames;
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#property (strong, nonatomic) NSMutableArray *imageObjects;
#property (strong, nonatomic) AWSS3TransferManager *transferManager;
#end
ViewController.M
#interface UIViewController () {
}
#end
#implementation tableTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.transferManager = [AWSS3TransferManager defaultS3TransferManager];
self.view.backgroundColor = [UIColor whiteColor];
[self listAllObjects];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)cameraRoll:(id)sender {
UIImagePickerController *iPhonePicker = [[UIImagePickerController alloc]init];
[iPhonePicker setDelegate:self];
//UIPopoverController *iPadPicker = [[UIPopoverController alloc]init];
UIImagePickerController *iPadPicker = [[UIImagePickerController alloc]init];
[iPadPicker setDelegate:self];
if ([[UIDevice currentDevice]userInterfaceIdiom]==UIUserInterfaceIdiomPhone) {
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
[iPhonePicker allowsEditing];
[iPhonePicker setSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
}
else {
[iPhonePicker setAllowsEditing:YES];
[iPhonePicker setSourceType:UIImagePickerControllerSourceTypeCamera];
}
[self presentViewController:iPhonePicker animated:YES completion:nil];
}
// else if([[UIDevice currentDevice]userInterfaceIdiom]==UIUserInterfaceIdiomPad) {
// if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
// [iPadPicker setAllowsEditing:YES];
// [iPadPicker setSourceType:UIImagePickerControllerSourceTypeCamera];
// }
// else {
// [iPadPicker allowsEditing];
// [iPadPicker setSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
//CREATE POPOVER
// }
}
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
[self.image setImage:image];
[self uploadImage:info];
if ([[UIDevice currentDevice]userInterfaceIdiom]==UIUserInterfaceIdiomPhone) {
[self dismissViewControllerAnimated:YES completion:nil];
}
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
}
-(void) uploadImage:(NSDictionary*)info {
imageObject *a = [imageObject new];
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
NSString *imagePath = [NSTemporaryDirectory() stringByAppendingPathComponent:#"upload-image.tmp"];
NSData *imageData = UIImagePNGRepresentation(image);
NSString *fileName = [[NSString alloc] initWithFormat:#"%f.jpg", [[NSDate date] timeIntervalSince1970 ] ];
[imageData writeToFile:imagePath atomically:YES];
a.image = image;
a.key = fileName;
[self.imageObjects addObject:a];
AWSS3TransferManagerUploadRequest *uploadRequest = [AWSS3TransferManagerUploadRequest new];
uploadRequest.bucket = #"karanphotos";
uploadRequest.key = fileName;
uploadRequest.body = [NSURL fileURLWithPath:imagePath];
[[self.transferManager upload:uploadRequest] continueWithExecutor:[AWSExecutor mainThreadExecutor] withBlock:^id(AWSTask *task) {
if (task.error != nil) {
NSLog(#"%# is causing error", uploadRequest.key);
}
else {
NSLog(#"Upload successful");
}
return nil;
}];
}
-(void) listAllObjects {
AWSS3 *S3 = [AWSS3 defaultS3];
AWSS3ListObjectsRequest *listObjects = [AWSS3ListObjectsRequest new];
listObjects.bucket = #"karanphotos";
self.imageNames = [NSMutableArray new];
self.imageObjects = [NSMutableArray new];
[[S3 listObjects:listObjects]continueWithBlock:^id(AWSTask *task) {
if (task.error) {
NSLog(#"listObjects failed-->%#", task.error);
}
else {
AWSS3ListObjectsOutput *output = task.result;
for (AWSS3Object *temp in output.contents) {
imageObject *a = [imageObject new];
a.key = temp.key;
[self.imageObjects addObject:a];
}
}
[self downloadImages:self.imageObjects];
return nil;
}];
}
-(void) downloadImages:(NSMutableArray *)imageNames {
for (imageObject *a in imageNames) {
NSString *downloadingFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:#"downloaded-%#", a.key]];
NSURL *url = [NSURL fileURLWithPath:downloadingFilePath];
AWSS3TransferManagerDownloadRequest *download = [AWSS3TransferManagerDownloadRequest new];
download.bucket = #"karanphotos";
download.key = a.key;
download.downloadingFileURL = url;
[[self.transferManager download:download] continueWithExecutor:[AWSExecutor mainThreadExecutor] withBlock:^id(AWSTask *task) {
if (task.error) {
if ([task.error.domain isEqualToString:AWSS3TransferManagerErrorDomain]) {
switch (task.error.code) {
case AWSS3TransferManagerErrorCancelled:
case AWSS3TransferManagerErrorPaused:
break;
default:
NSLog(#"Error: %#", task.error);
break;
}
}
else {
NSLog(#"%#", task.error);
}
}
if (task.result) {
AWSS3TransferManagerDownloadOutput *downloadOutput = task.result;
NSLog(#"success");
UIImage *image = [[UIImage alloc]initWithData:[NSData dataWithContentsOfFile:downloadOutput.body]];
a.image = image;
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
}
return nil;
}];
}
}
- (IBAction)editButton:(id)sender {
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
imageObject *a = [self.imageObjects objectAtIndex:indexPath.row];
self.image.image = a.image;
cell.textLabel.text = a.key;
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
imageObject *a = [self.imageObjects objectAtIndex:indexPath.row];
self.image.image = a.image;
}
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
// Return NO if you do not want the specified item to be editable.
return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
imageObject *a = [self.imageObjects objectAtIndex:indexPath.row];
[self.imageObjects removeObject:a];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
AWSS3DeleteObjectRequest *deleteReqest = [AWSS3DeleteObjectRequest new];
deleteReqest.bucket = #"karanphotos";
deleteReqest.key = a.key;
[self deleteObjectFromBucket:deleteReqest];
} }
-(void)deleteObjectFromBucket:(AWSS3DeleteObjectRequest *)deleteRequest {
AWSS3 *s3 = [AWSS3 defaultS3];
[[s3 deleteObject:deleteRequest] continueWithBlock:^id(AWSTask *task) {
if(task.error){
if(task.error.code != AWSS3TransferManagerErrorCancelled && task.error.code != AWSS3TransferManagerErrorPaused){
NSLog(#"Error: [%#]", task.error);
}
}
else {
NSLog(#"Successfully deleted");
}
dispatch_async(dispatch_get_main_queue(), ^{
if (self.imageObjects.count == 0) {
[self.image setImage:nil];
[self.tableView reloadData];
}
});
return nil;
}];
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
}
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
#pragma mark - Navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.imageObjects.count;
}
#end
Had a little bit of trouble replacing my TableViewController with PFQueryTableViewController, but I got it working with pull to refresh and pagination. However, I can't get the cache to work (at the very bottom of the .m file). Any ideas on what's going on?
The only other change I made here was subclass the image in the cell as PFImage.
ContactsTableViewController.h
#import <UIKit/UIKit.h>
#import <Parse/Parse.h>
#import "FilterViewController.h"
#interface ContactsTableViewController : PFQueryTableViewController <UITableViewDelegate>
#property (nonatomic) NSString *titleName;
#property (nonatomic) NSString *date;
#property (nonatomic) NSString *price;
#property (nonatomic) NSString *imageName;
#property (nonatomic) NSString *venue;
#property (nonatomic) UIImage *image;
#property (nonatomic) NSString *filter;
#property (nonatomic) NSArray *eventsArray;
-(void)retrieveEvents;
-(void)filterEvents;
#end
ContactsTableViewController.m
#import "ContactsTableViewController.h"
#import "CustomCellTableViewCell.h"
#import "DetailViewController.h"
#interface ContactsTableViewController ()
#end
#implementation ContactsTableViewController
- (id)initWithCoder:(NSCoder *)aCoder
{
self = [super initWithCoder:aCoder];
if (self) {
// The className to query on
self.parseClassName = #"eventsList";
// The key of the PFObject to display in the label of the default cell style
// self.textKey = #"name";
// Whether the built-in pull-to-refresh is enabled
self.pullToRefreshEnabled = YES;
// Whether the built-in pagination is enabled
self.paginationEnabled = NO;
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self performSelector:#selector(retrieveEvents)];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(filterEvents) name:#"updateParent" object:nil];
self.view.backgroundColor = [UIColor colorWithRed:245/255.0 green:243/255.0 blue:240/255.0 alpha:1];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.eventsArray count];
}
// Parse Method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object
{
static NSString *CellIdentifier = #"cellID";
CustomCellTableViewCell *customCell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
NSDictionary *tempDict = [self.eventsArray objectAtIndex:indexPath.row];
self.titleName = [tempDict objectForKey:#"eventTitle"];
self.price = [tempDict objectForKey:#"eventPrice"];
self.date = [tempDict objectForKey:#"eventDate"];
self.venue = [tempDict objectForKey:#"eventVenue"];
PFFile *imageFile = [tempDict objectForKey:#"eventImage"];
[imageFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if (!error) {
customCell.customImageView.image = [UIImage imageWithData:data];
}
}];
customCell.titleLabel.text = self.titleName;
customCell.priceLabel.text = self.price;
customCell.customDateLabel.text = self.date;
customCell.venueNameLabel.text = self.venue;
return customCell;
}
- (void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
[cell setBackgroundColor:[UIColor darkGrayColor]];
tableView.separatorColor = [UIColor clearColor];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"showEventDetail"]) {
DetailViewController *destinationVC = [[DetailViewController alloc] init];
destinationVC = segue.destinationViewController;
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSDictionary *tempDict = [self.eventsArray objectAtIndex:indexPath.row];
destinationVC.eventTitle = [tempDict objectForKey:#"eventTitle"];
destinationVC.eventPrice = [tempDict objectForKey:#"eventPrice"];
destinationVC.eventDate = [tempDict objectForKey:#"eventDate"];
destinationVC.venueName = [tempDict objectForKey:#"eventVenue"];
destinationVC.navigationItem.title = [tempDict objectForKey:#"eventTitle"];
// Image
PFFile *imageFile = [tempDict objectForKey:#"eventImage"];
[imageFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if (!error) {
destinationVC.eventImageView.image = [UIImage imageWithData:data];
destinationVC.eventImage = [UIImage imageWithData:data];
}
}];
// GeoPoint
destinationVC.geoPoint = [tempDict objectForKey:#"GeoPoint"];
} else if ([segue.identifier isEqualToString:#"showFilterTable"]){
FilterViewController *vc = (FilterViewController *)[[[segue destinationViewController] viewControllers] objectAtIndex:0];
[vc setDelegate:self];
}
}
-(void)retrieveEvents
{
PFQuery *retrieveEvents = [PFQuery queryWithClassName:#"eventsList"];
[retrieveEvents setLimit:300];
[retrieveEvents orderByAscending:#"eventTitle"];
[retrieveEvents findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
self.eventsArray = [[NSArray alloc] initWithArray:objects];
}
[self.tableView reloadData];
}];
}
-(void)filterEvents
{
if ([self.filter isEqualToString:#"All Events"]) {
[self performSelector:#selector(retrieveEvents)];
return;
}
NSLog(#"retrieveEvents: %#", self.filter);
PFQuery *retrieveEvents = [PFQuery queryWithClassName:#"eventsList"];
[retrieveEvents whereKey:#"eventType" equalTo:self.filter];
[retrieveEvents setLimit:300];
[retrieveEvents orderByAscending:#"eventTitle"];
[retrieveEvents findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
self.eventsArray = [[NSArray alloc] initWithArray:objects];
NSLog(#"%#", self.eventsArray);
}
[self.tableView reloadData];
}];
}
// Parse Method
- (PFQuery *)queryForTable
{
PFQuery *query = [PFQuery queryWithClassName:self.parseClassName];
query.cachePolicy = kPFCachePolicyCacheThenNetwork;
return query;
}
#end
From the looks of it you are not using the queryForTable to populate the tableview, you are using your separate query.
This query never gets used in your tableview
- (PFQuery *)queryForTable
{
PFQuery *query = [PFQuery queryWithClassName:self.parseClassName];
query.cachePolicy = kPFCachePolicyCacheThenNetwork;
return query;
}
Instead this one does:
-(void)retrieveEvents
{
PFQuery *retrieveEvents = [PFQuery queryWithClassName:#"eventsList"];
[retrieveEvents setLimit:300];
[retrieveEvents orderByAscending:#"eventTitle"];
[retrieveEvents findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
self.eventsArray = [[NSArray alloc] initWithArray:objects];
}
[self.tableView reloadData];
}];
}
kPFCachePolicyCacheThenNetwork means to use both cache and network (first get from cache for quickness, then get from network for up-to-date-ness the next time). Try instead using kPFCachePolicyCacheElseNetwork.
Try this code. It may not be perfect. But I believe it should at least head you in the right direction.
#import "ContactsTableViewController.h"
#import "CustomCellTableViewCell.h"
#import "DetailViewController.h"
#interface ContactsTableViewController ()
#end
#implementation ContactsTableViewController
- (id)initWithCoder:(NSCoder *)aCoder
{
self = [super initWithCoder:aCoder];
if (self) {
// The className to query on
self.parseClassName = #"eventsList";
// The key of the PFObject to display in the label of the default cell style
// self.textKey = #"name";
// Whether the built-in pull-to-refresh is enabled
self.pullToRefreshEnabled = YES;
// Whether the built-in pagination is enabled
self.paginationEnabled = NO;
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(filterEvents) name:#"updateParent" object:nil];
self.view.backgroundColor = [UIColor colorWithRed:245/255.0 green:243/255.0 blue:240/255.0 alpha:1];
tableView.separatorColor = [UIColor clearColor];
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
//This reloaded the PFQueryTableView
[self loadObjects];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return self.objects.count;
}
// Parse Method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object
{
static NSString *CellIdentifier = #"cellID";
CustomCellTableViewCell *customCell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
PFObject *object = [self objectAtIndexPath:indexPath];
customCell.titleLabel.text = object[#"eventTitle"];
customCell.priceLabel.text = object[#"eventPrice"];
customCell.customDateLabel.text = object[#"eventDate"];
customCell.venueNameLabel.text = object[#"eventVenue"];
PFFile *imageFile = [tempDict objectForKey:#"eventImage"];
[imageFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if (!error) {
customCell.customImageView.image = [UIImage imageWithData:data];
}
}];
return customCell;
}
- (void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
[cell setBackgroundColor:[UIColor darkGrayColor]];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"showEventDetail"]) {
DetailViewController *destinationVC = [[DetailViewController alloc] init];
destinationVC = segue.destinationViewController;
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSDictionary *tempDict = [self.eventsArray objectAtIndex:indexPath.row];
destinationVC.eventTitle = [tempDict objectForKey:#"eventTitle"];
destinationVC.eventPrice = [tempDict objectForKey:#"eventPrice"];
destinationVC.eventDate = [tempDict objectForKey:#"eventDate"];
destinationVC.venueName = [tempDict objectForKey:#"eventVenue"];
destinationVC.navigationItem.title = [tempDict objectForKey:#"eventTitle"];
// Image
PFFile *imageFile = [tempDict objectForKey:#"eventImage"];
[imageFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if (!error) {
destinationVC.eventImageView.image = [UIImage imageWithData:data];
destinationVC.eventImage = [UIImage imageWithData:data];
}
}];
// GeoPoint
destinationVC.geoPoint = [tempDict objectForKey:#"GeoPoint"];
} else if ([segue.identifier isEqualToString:#"showFilterTable"]){
FilterViewController *vc = (FilterViewController *)[[[segue destinationViewController] viewControllers] objectAtIndex:0];
[vc setDelegate:self];
}
}
// Parse Method
-(NSString *)filter
{
return _filter;
}
-(void)setFilter
{
_filter = filter;
[self loadObjects];
}
- (PFQuery *)queryForTable
{
PFQuery *query = [PFQuery queryWithClassName:self.parseClassName];
query.cachePolicy = kPFCachePolicyCacheThenNetwork;
if (self.filter && ![self.filter isEqualToString:#"All Events"]) [query whereKey:#"eventTitle" equalTo:self.filter];
[query setLimit:300];
[query orderByAscending:#"eventTitle"];
return query;
}
#end
In my app, there's only 2 views. First view is a collection view and when you tap on an image, it goes to the MWPhotoBrowser to view the image in it's full size.
I'm retrieving ~100 images over the internet and adding them to a NSMutableArray.
There's a problem with this. When I run the app for the first time and select a thumbnail image from the grid it shows the last image. Not the one I selected. Note that I emphasized on the first time because it only happens in the first time. If I go back and tap on another image, it correctly shows the selected one. Below is a screenshot of how its supposed to work.
Here is the code
#import "UIImageView+WebCache.h"
#import "ViewController.h"
#import "MWPhotoBrowser.h"
#import "Image.h"
#import "ImageCell.h"
#interface ViewController () <UICollectionViewDelegate, UICollectionViewDataSource, MWPhotoBrowserDelegate>
#property (strong, nonatomic) NSMutableArray *images;
#property (strong, nonatomic) NSMutableArray *browserImages;
#property (strong, nonatomic) MWPhotoBrowser *browser;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.browser = [[MWPhotoBrowser alloc] initWithDelegate:self];
self.browser.displayActionButton = YES;
self.browser.displayNavArrows = YES;
self.browser.displaySelectionButtons = NO;
self.browser.zoomPhotosToFill = YES;
self.browser.alwaysShowControls = YES;
self.browser.enableGrid = NO;
self.browser.startOnGrid = NO;
self.browser.wantsFullScreenLayout = NO;
[self.browser showNextPhotoAnimated:YES];
[self.browser showPreviousPhotoAnimated:YES];
[self loadImages];
}
- (void)loadImages
{
self.images = [[NSMutableArray alloc] init];
self.browserImages = [[NSMutableArray alloc] init];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"%#%#", HOST_URL, #"All_Images.php"]];
NSData *jsonResults = [NSData dataWithContentsOfURL:url];
NSDictionary *results = [NSJSONSerialization JSONObjectWithData:jsonResults options:0 error:NULL];
NSDictionary *images = results[#"Images"];
for (NSDictionary *img in images) {
Image *imageObj = [[Image alloc] init];
imageObj.imageId = [img objectForKey:#"id"];
imageObj.imageName = [img objectForKey:#"name"];
// Get the full image path
NSString *fullImagePath = [NSString stringWithFormat:#"%#%#", HOST_URL, [img objectForKey:#"full_image"]];
imageObj.imagePath = fullImagePath;
// Get the thumbnail image path depending on the device
NSString *thumbnailPath;
if (DEVICE_IS_PAD) {
thumbnailPath = [NSString stringWithFormat:#"%#%#", HOST_URL, [img objectForKey:#"thumbnail_ipad"]];
} else {
thumbnailPath = [NSString stringWithFormat:#"%#%#", HOST_URL, [img objectForKey:#"thumbnail_iphone"]];
}
imageObj.imageThumbnail = thumbnailPath;
// Creates an object for each image and fill it with the retrieved info
[self.images addObject:imageObj];
// This array stores the image paths for later use (displaying them in a photo browser)
MWPhoto *browserImage = [MWPhoto photoWithURL:[NSURL URLWithString:imageObj.imagePath]];
browserImage.caption = imageObj.imageName;
[self.browserImages addObject:browserImage];
}
[self.collectionView reloadData];
}
#pragma mark - MWPhotoBrowserDelegate
- (NSUInteger)numberOfPhotosInPhotoBrowser:(MWPhotoBrowser *)photoBrowser
{
return self.browserImages.count;
}
- (id <MWPhoto>)photoBrowser:(MWPhotoBrowser *)photoBrowser photoAtIndex:(NSUInteger)index
{
if (index < self.browserImages.count) {
return self.browserImages[index];
}
return nil;
}
#pragma mark - UICollectionViewDataSource
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return self.images.count;
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"ImageCell";
ImageCell *cell = (ImageCell *)[collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
Image *image = self.images[indexPath.row];
[cell.imageView setImageWithURL:[NSURL URLWithString:image.imageThumbnail] placeholderImage:[UIImage imageNamed:#"placeholder"]];
return cell;
}
#pragma mark - UICollectionViewDelegate
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
// Opens the image browser
[self.browser setCurrentPhotoIndex:indexPath.row];
[self.navigationController pushViewController:self.browser animated:YES];
}
#end
I cannot find out why it shows the last image of the grid the first time I select an image. I have uploaded a demo project with the issue so it'll be easier for you to take a quick look at it.
https://www.dropbox.com/s/tp6a67f83l0rzin/PhotoBrowserTest.zip
I'd really appreciate anyone's help to correct this problem.
Thank you.
Change in your project these methods
- (NSUInteger)numberOfPhotos {
if (_photoCount == NSNotFound || _photoCount == 0) {
if ([_delegate respondsToSelector:#selector(numberOfPhotosInPhotoBrowser:)]) {
_photoCount = [_delegate numberOfPhotosInPhotoBrowser:self];
} else if (_depreciatedPhotoData) {
_photoCount = _depreciatedPhotoData.count;
}
}
if (_photoCount == NSNotFound) _photoCount = 0;
return _photoCount;
}
AND
- (id)initWithDelegate:(id <MWPhotoBrowserDelegate>)delegate {
if ((self = [self init])) {
_delegate = delegate;
[self setCurrentPhotoIndex:0];
}
return self;
}
You need to check if your _photoCount == 0, because the first time you donĀ“t have this info and _photoCount will be 0, but the second time your numberOfPhotosInPhotoBrowser will be the right