I'm trying to parse a list of objects that the current user has created to a custom table view from Parse.com. I'm getting this error when I run it:
[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array
Here's how I'm doing it:
#interface ProfileViewController ()
#property (nonatomic, retain) PFQuery *query;
#end
#implementation DailyProfileViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self refresh];
self.tableView.delegate = self;
_projects = [[NSMutableArray alloc] initWithCapacity:100];
}
- (void)refresh {
PFQuery *query = [PFQuery queryWithClassName:#"Projects"];
[query includeKey:#"user"];
[query whereKey:#"user" equalTo:[PFUser currentUser]];
[query orderByDescending:#"createdAt"];
[query findObjectsInBackgroundWithBlock:^(NSArray *posts, NSError *error) {
if (!error) {
[_projects setArray:posts];
[self.tableView reloadData];
NSLog(#"%#", posts);
return;
}
NSLog(#"Fetch posts error: %#", error.localizedDescription);
return;
}];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _projects.count;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 65;
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
_project = [_projects objectAtIndex:indexPath.row];
ProfileProjectTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"ProfileProjectTableViewCell"];
if (!_user) _user = [PFUser currentUser];
cell.item = _project;
[(PFFile*)_project[#"profilePic"] getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
cell.profilePic.image = [UIImage imageWithData:data];
}];
[(PFFile*)_project[#"bgImage"] getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
cell.bgView.image = [UIImage imageWithData:data];
}];
cell.projectName.text = _project[#"name"];
return cell;
}
#end
Please change your viewDidLoad like this..
self.tableView.delegate = self;
_projects = [[NSMutableArray alloc]init];
[self refresh];
you should call refresh method after intializing array and make sure that the data you are adding should not empty
Why are you calling - refresh before initialising your array? Change your -viewDidLoad as such:
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.delegate = self;
_projects = [[NSMutableArray alloc] init];
[self refresh];
}
Related
I have refresh method when user pulls down and it seems like it doesn't update the array count and just crashes:
Here is the crash:
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 9 beyond bounds [0 .. 8]'
Here is my code:
Query Data: (used to refresh as well)
- (void) queryData
{
PFObject *queryPhotos = self.userInformationObject;
PFQuery *query = [PFQuery queryWithClassName:#"Photo"];
[query whereKey:#"userTookPhoto" equalTo:queryPhotos];
[query orderByAscending:#"createdAt"];
[query findObjectsInBackgroundWithBlock:^(NSArray * _Nullable objects, NSError * _Nullable error) {
if (!error) {
imageFilesArray = [[NSArray alloc] initWithArray:objects];
[self.myCollectionView reloadData];
[self.refreshControl endRefreshing];
}
}];
}
CellForItemAtIndexPath
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
static NSString * const reuseIdentifier = #"imageCell";
imageCollectionCell *cell = [self.myCollectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
// Configure the cell
cell.layer.borderColor = [UIColor grayColor].CGColor;
cell.layer.borderWidth = 0.5;
cell.layer.cornerRadius = 7.0f;
cell.clipsToBounds = YES;
PFObject *imageObject = [imageFilesArray objectAtIndex:indexPath.row];
PFFile *imageFile = [imageObject objectForKey:#"image"];
[imageFile getDataInBackgroundWithBlock:^(NSData * _Nullable data, NSError * _Nullable error) {
if (!error) {
cell.imageViewCell.image = [UIImage imageWithData:data];
}
else{
NSLog(#"Fail");
}
} progressBlock:^(int percentDone) {
}];
return cell;
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
//#warning Incomplete implementation, return the number of sections
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
//#warning Incomplete implementation, return the number of items
return [imageFilesArray count];
}
This is all the code relating to the refresh, and showing the cells, I dont know whats going wrong, hope someone has an answer.
Thanks in advance.
Try below code.
- (void) queryData
{
[self.refreshControl endRefreshing];
PFObject *queryPhotos = self.userInformationObject;
PFQuery *query = [PFQuery queryWithClassName:#"Photo"];
[query whereKey:#"userTookPhoto" equalTo:queryPhotos];
[query orderByAscending:#"createdAt"];
[query findObjectsInBackgroundWithBlock:^(NSArray * _Nullable objects, NSError * _Nullable error) {
if (!error) {
imageFilesArray = [[NSArray alloc] initWithArray:objects];
}
}];
[self.myCollectionView reloadData];
}
I have tried following code so far:
PFGeoPoint * myGeoPoint = [PFUser currentUser][#"coordinates"]; // Your geoPoint
PFQuery *query = [PFUser query];
[query includeKey:#"User"];
[query whereKey:#"coordinates" nearGeoPoint:myGeoPoint withinMiles:radiusInMiles];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if(!error){
for (PFUser *object in objects){
users = (NSArray*)[object ObjectForKey:#"User"];
}
[self.tableView reloadData];
}
}
}];
- (PFUser*) objectAtIndexPath:(NSIndexPath*)indexPath {
PFUser *object = [PFUser objectWithClassName: #"User"];
[object setObject:[users objectAtIndex:indexPath.row] forKey:#"User"];
return object;
}
// Use myObjects for numberOfRowsInSection:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection: (NSInteger)section {
return users.count;
}
//Use your custom object for cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath object:(PFUser *)object {
static NSString *simpleTableIdentifier = #"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
// Configure the cell using object
UILabel *reviewLabel = (UILabel *)[cell viewWithTag:10];
reviewLabel.text = [object objectForKey:object.username];
PFFile *userImageFile = object[#"profilePic"];
[userImageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
if (!error) {
if (imageData != nil)
cell.imageView.image = [UIImage imageWithData:imageData];
else cell.imageView.image= [UIImage imageNamed:#"defaultPerson"];
}
}];
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
SMChatViewController *chatController = [SMChatViewController alloc];
// [chatController initWithPhoto:image];
[self presentModalViewController:chatController animated:YES];
}
In this code I am retrieving an array of PFUsers as "objects".When I am saving the objects array to users it returns as empty. So can anyone please suggest me something that How can I set the username and profilepic in a tableView?
I guess query is not correct.
Try this:
PFGeoPoint * myGeoPoint = [PFUser currentUser][#"coordinates"]; // Your geoPoint
PFQuery *query = [PFQuery queryWithObject:#"_User"];
NSArray *userList = [NSArray new];
[query whereKey:#"coordinates" nearGeoPoint:myGeoPoint withinMiles:radiusInMiles];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if(!error){
userList = objects;
[self.tableView reloadData];
}
}];
In your code you're asking 'User' objects, then you fetching 'User' field from this objects.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {
static NSString *simpleTableIdentifier = #"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
PFUser *user = (PFUser*)[users objectAtIndex:indexPath.row];
cell.textLabel.text=user.username;
PFFile *userImageFile = user[#"profilePic"];
[userImageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
if (!error) {
if (imageData != nil)
cell.imageView.image = [UIImage imageWithData:imageData];
else cell.imageView.image= [UIImage imageNamed:#"defaultPerson.png"];
}
}];
return cell;
}
I'm currently building a photo messaging app where users can send photos to each other. When the photo is taken, you select recipients from a UITableView in a new View Controller.
But every time I select a person from the list and send the photo, it gets the wrong user.objectId. It seems to take the Friendship objectId which is another class named Friendship, when it should take the objectId of the user. Here's how I'm doing it:
#implementation PickRecipientsViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.recipients = [[NSMutableArray alloc] init];
[_selectedImage setImage:_image];
self.tableView.delegate = self;
[self refreshFriends];
}
- (void)refreshFriends {
[__acceptedRequests removeAllObjects];
PFQuery *friendsQuery = [self queryForFriends];
PFQuery *acceptedRequestQuery = [self queryForAcceptedFriendRequests];
PFQuery *friendRequestsQuery = [self queryForRequests];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
// Find friends
NSArray *objects = [friendsQuery findObjects];
for (PFObject * obj in objects) {
[obj[#"user1"] fetchIfNeeded];
[obj[#"user2"] fetchIfNeeded];
}
_friends = [objects mutableCopy];
// Find pending requests
objects = [friendRequestsQuery findObjects];
for (PFObject *obj in objects) {
[obj[#"fromUser"] fetchIfNeeded];
}
__friendRequests = [objects mutableCopy];
// Find accepted requests
objects = [acceptedRequestQuery findObjects];
for (PFObject *obj in objects) {
PFUser *to = (PFUser*)[obj[#"toUser"] fetchIfNeeded];
[obj deleteEventually];
[__acceptedRequests addObject:to[#"username"]];
}
// show accepted requests
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
if (__acceptedRequests.count > 0) {
NSString *friends = __acceptedRequests[0];
for (int i = 1; i < __acceptedRequests.count; ++i) {
friends = [friends stringByAppendingFormat:#", %#", __acceptedRequests[i]];
}
friends = [friends stringByAppendingString:#" accepted your friend request"];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"New Friends" message:friends delegate:self cancelButtonTitle:#"Wuhu" otherButtonTitles:nil, nil];
alert.tag = kAlertTagAcceptedRequest;
[alert show];
}
});
});
}
- (PFQuery *)queryForAcceptedFriendRequests {
PFUser *user = [PFUser currentUser];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"status = %# AND (fromUser = %# AND toUser != %#)", #"approved", user, user];
PFQuery *acceptedRequestQuery = [PFQuery queryWithClassName:#"FriendRequest" predicate:predicate];
return acceptedRequestQuery;
}
- (PFQuery *)queryForFriends {
PFUser *user = [PFUser currentUser];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"user1 = %# AND user2 != %# OR user1 != %# AND user2 = %#", user, user, user, user];
PFQuery *friendsQuery = [PFQuery queryWithClassName:#"Friendship" predicate:predicate];
return friendsQuery;
}
- (PFQuery *)queryForRequests {
PFUser *user = [PFUser currentUser];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"status = %# AND (toUser = %# AND fromUser != %#)", #"pending", user, user];
PFQuery *friendRequests = [PFQuery queryWithClassName:#"FriendRequest" predicate:predicate];
return friendRequests;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
RecipientsTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"RecipientsTableViewCell" forIndexPath:indexPath];
PFUser *user = [self.friends objectAtIndex:indexPath.row];
if([self.recipients containsObject:user.objectId]){
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}else{
cell.accessoryType = UITableViewCellAccessoryNone;
}
PFObject *friendRequest = [_friends objectAtIndex:indexPath.row];
PFUser *user1 = (PFUser *)friendRequest[#"user1"];
PFUser *user2 = (PFUser *)friendRequest[#"user2"];
if ([user1.username isEqualToString:[PFUser currentUser].username]) {
cell.nameL.text = user2[#"username"];
[(PFFile*)user2[#"profilePic"] getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if (error) {return;}
cell.profilePic.image = [UIImage imageWithData:data];
}];
} else if ([user2.username isEqualToString:[PFUser currentUser].username]) {
cell.nameL.text = user1[#"username"];
[(PFFile*)user1[#"profilePic"] getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if (error) {return;}
cell.profilePic.image = [UIImage imageWithData:data];
}];
}
return cell;
}
- (BOOL)isFriend:(PFUser *)user {
for (PFUser *friend in self.friends) {
if ([friend.objectId isEqualToString:user.objectId]) {
return YES;
}
}
return NO;
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _friends.count;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 68;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self.tableView deselectRowAtIndexPath:indexPath animated:NO];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
PFUser *user = [self.friends objectAtIndex:indexPath.row];
if (cell.accessoryType == UITableViewCellAccessoryNone){
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[self.recipients addObject:user.objectId];
} else{
cell.accessoryType = UITableViewCellAccessoryNone;
[self.recipients removeObject:user.objectId];
}
}
- (IBAction)sendImage {
PFObject *message = [PFObject objectWithClassName:#"Messages"];
[message setObject:[PFUser currentUser] forKey:#"fromUser"];
[message setObject:[PFUser currentUser] forKey:#"toUser"];
[message setObject:#"image" forKey:#"fileType"];
[message setObject:self.recipients forKey:#"recipientIds"];
[message setObject:[[PFUser currentUser] objectId] forKey:#"senderId"];
// Image
NSData *imageData = UIImageJPEGRepresentation(_image, 1.0);
NSString *filename = [NSString stringWithFormat:#"image.png"];
PFFile *imageFile = [PFFile fileWithName:filename data:imageData];
[message setObject:imageFile forKey:#"file"];
[message saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (!error) {
// Dismiss the controller
[[[self presentingViewController] presentingViewController] dismissViewControllerAnimated:YES completion:nil];
} else {
[SVProgressHUD showErrorWithStatus:#"Oh darn! Something went wrong :("];
}
}];
}
#end
Because _friends is an array of Friendship objects and when a row is tapped you just directly get it out of the array and don't then get the appropriate user from it (like you do when you configure the cell labels).
So in tableView:didSelectRowAtIndexPath: you should have something like:
BOOL adding = NO;
if (cell.accessoryType == UITableViewCellAccessoryNone){
cell.accessoryType = UITableViewCellAccessoryCheckmark;
adding = YES;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
PFObject *friendRequest = [_friends objectAtIndex:indexPath.row];
PFUser *user1 = (PFUser *)friendRequest[#"user1"];
PFUser *user2 = (PFUser *)friendRequest[#"user2"];
PFUser *recipient = nil;
if ([user1.username isEqualToString:[PFUser currentUser].username]) {
recipient = user2;
} else if ([user2.username isEqualToString:[PFUser currentUser].username]) {
recipient = user1;
}
if (adding) {
[self.recipients addObject:recipient.objectId];
} else {
[self.recipients removeObject:recipient.objectId];
}
Here is the code for the data I am passing on to the scene with the image:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[super tableView:tableView didSelectRowAtIndexPath:indexPath];
rowNo = indexPath.row;
PFUser *currentUser = [PFUser currentUser];
PFQuery *query = [PFQuery queryWithClassName:#"Photo"];
[query whereKey:#"username" equalTo:currentUser.username];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
_photo = [objects objectAtIndex:rowNo];
}];
[self performSegueWithIdentifier:#"showImageCloseup" sender:self];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
ImageCloseupViewController *destination = [segue destinationViewController];
destination.photoObject = _photo;
}
And here is the code which loads the image:
- (void)viewDidLoad
{
[super viewDidLoad];
PFFile *p = [_photoObject objectForKey:#"photo"];
[p getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if(!error){
UIImage *image = [UIImage imageWithData:data];
[_imageView setImage:image];
}
}];
For some reason, the image is not loading, why is this is so? How can I fix it?
This:
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
_photo = [objects objectAtIndex:rowNo];
}];
[self performSegueWithIdentifier:#"showImageCloseup" sender:self];
Needs to be:
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
_photo = [objects objectAtIndex:rowNo];
[self performSegueWithIdentifier:#"showImageCloseup" sender:self];
}];
Because:
// Runs 1st - executes in background thread stores block, then runs block once it's done
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
// Runs 3rd - already segued at this point
_photo = [objects objectAtIndex:rowNo];
}];
// Runs 2nd - starts segue
[self performSegueWithIdentifier:#"showImageCloseup" sender:self];
However, this seems like there's an overall problem with your design pattern. If you already have access to objects, you shouldn't have to requery the entire database each time. Do you have a reference to the array populating the tableView? If so, something like this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[super tableView:tableView didSelectRowAtIndexPath:indexPath];
rowNo = indexPath.row;
_photo = yourDataArray[indexPath.row];
[self performSegueWithIdentifier:#"showImageCloseup" sender:self];
}
I am using Parse.com for retrieving my data.I want to retrieve my images from parse via pf query but my approach does not working.I get nothing where my UIImageView is. Here is my code:
PFQuery *query = [PFQuery queryWithClassName:#"Class"];
[query whereKey:#"Yes or No" equalTo:[NSNumber numberWithBool:YES]];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// The find succeeded.
NSLog(#"Successfully retrieved %d scores.", objects.count);
for (int i = 0; i < objects.count; i++) {
object = [objects objectAtIndex:i];
NSString *Property1 = [object objectForKey:#"Property1"];
__block UIImage *MyPicture = [[UIImage alloc]init];
PFFile *imageFile = [object objectForKey:#"Resimler"];
[imageFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error){
if (!error) {
MyPicture = [UIImage imageWithData:data];
}
}];
aClass *AC = [[aClass alloc]initWithProperty:Propert1 Picture:MyPicture];
[self.MyArray addObject:AC];
}
}
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
MyViewViewCell *cell = (MyViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"Cell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
aClass *mC = [self.MyArray objectAtIndex:indexPath.row];
cell.Label.text = mC.Property;
cell.myImage.image = mC.Picture;
return cell;
}
Edit:
At aClass.h
#interface aClass : NSObject
#property(strong)NSString *Property;
#property(strong)UIImage *Resim;
-(id)initWithProperty:(NSString *)aProperty Picture:(UIImage *)aPicture ;
#end
at aClass.m
#implementation Mekan
#synthesize Property, Picture;
-(id)initWithMekanIsmi:(NSString *)aProperty Picture:(UIImage *)aPicture{
self=[super init];
if(self){
self.Property = aProperty;
self.Picture = aPicture;
}
return self;
}
#end
I know it is kind of a mass code but i have to write those codes to illustrate where i assign myImage. So you can ask where you do not understand
I do it like this:
UIImageView *imageView = [[UIImageView alloc] initWithImage:#"default.png"];
[userIcon getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
imageView.image = [[UIImage alloc] initWithData:data];
} progressBlock:^(int percentDone) {
// update progress
}];
You seem to be assigning it to a UIImage properly, but never setting that image as the image for a UIImageView.