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];
}
Related
I am trying to search through a list of users in my Parse database. To do so I have a search bar controller and table view. When a user is searching, it seems like the search results are a letter behind. For example if I search "Be" it will show all the names starting with "B" instead of "Be" and when I search "Ben" it shows all the users starting with "Be".
Here is my textDidChange Method:
-(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{
NSString *string = searchText;
string = string.lowercaseString;
if(string.length>0){
PFUser *currentUser = [PFUser currentUser];
PFQuery *query = [PFQuery queryWithClassName:#"_User"];
[query whereKey:#"name_lower" containsString:string];
[query whereKey:#"username" notEqualTo:currentUser.username];
[query orderByAscending:#"name_lower"];
[query setLimit:1000];
[query findObjectsInBackgroundWithBlock:^(NSArray *array,NSError *error){
if(!error){
results = [[NSArray alloc]initWithArray:array];
[_mainTableView reloadData];
}else{
[ProgressHUD showError:#"Error Searching"];
}
}];
}else{
NSLog(#"NO RESULTS");
results = nil;
[_mainTableView reloadData];
}
}
Then in my cellforrow:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if (cell == nil) cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"cell"];
PFUser *user = results[indexPath.row];
[user fetchIfNeeded];
cell.textLabel.text = [NSString stringWithFormat:#"%# - #%#",user[#"name"],user[#"username"]];
cell.detailTextLabel.text = user[#"university"];
}
Hey try to put constraints like this:
[query whereKey:#"name_lower" hasPrefix:string];
instead of
[query whereKey:#"name_lower" containsString:string];
After all I would do it this way:
-(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{
NSString *string = searchText;
string = string.lowercaseString;
if(string.length>0){
PFQuery *query = [PFUser query];
[query whereKey:#"name_lower" hasPrefix:string];
[query whereKey:#"username" notEqualTo:[[PFUser currentUser] username]];
[query orderByAscending:#"name_lower"];
[query setLimit:1000];
[query findObjectsInBackgroundWithBlock:^(NSArray *array,NSError *error){
if(!error){
results = array;
[_mainTableView reloadData];
} else {
[ProgressHUD showError:#"Error Searching"];
}
}];
} else {
NSLog(#"NO RESULTS");
results = nil;
[_mainTableView reloadData];
}
}
I am using Parse as a backend of my app, and it seems that the profile photo is not displaying properly, shown in the image:
there is a black strip on john_appleseed's photo.
here is my code for saving the profile image:
NSData *profileData = UIImagePNGRepresentation(cell1.profileView.image);
PFFile *profileFile = [PFFile fileWithName:#"profilePhoto" data:profileData];
[profileFile saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error)
{
if (!error)
{
if (succeeded)
{
[user setObject:profileFile forKey:#"profilePhoto"];
[user saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error)
{
if (!error)
{
}
else
{
}
}];
}
}
}];
here is how I retrieve the image:(inside PFQueryTableViewController)
- (PFQuery *)queryForTable
{
//NSLog(#"called");
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
NSString *filter = [defaults objectForKey:#"topicFilter"];
NSLog(#"queryfortable: %#", filter);
PFQuery *query = [PFQuery queryWithClassName:#"Questions"];
[query includeKey:#"user"];
[query whereKey:#"category" equalTo:filter];
[query orderByDescending:#"createdAt"];
return query;
}
- (PFObject *)objectAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == self.objects.count)
{
return nil;//this is for the load more cell.
}
return [self.objects objectAtIndex:indexPath.section];
}
in - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object
PFUser *user = [object objectForKey:#"user"];
PFImageView *profileImgView = (PFImageView *)[cell viewWithTag:1];
profileImgView.layer.cornerRadius = profileImgView.frame.size.height/2;
profileImgView.layer.masksToBounds = YES;
PFFile *file = user[#"profilePhoto"];
profileImgView.file = file;
[profileImgView loadInBackground];
any ideas? many thanks.
You should be updating user interfaces on the main thread. Since your loading something in the background, you should notify the main thread that it needs to update an object. loadInBackground is downloading the file asynchronously.
Here is an example, that you can alter for your needs, just to illustrate, that updating UI components in the call back has it's benefits; this is based off of Parses own AnyPic:
NSString *requestURL = file.url; // Save copy of url locally (will not change in block)
[file getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if (!error) {
//dispatch on main thread
UIImage *image = [UIImage imageWithData:data];
} else {
NSLog(#"Error on fetching file");
}
}];
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];
}
I have a NSOperation that gets an array of message objects and cycles through them. For each message object I want to add a UIView to the current UIViewController. Only problem is I can't access the view from the NSOperation. Is there any way around this?
Thanks
code below (my main method in the NSOperation):
- (void)main {
//main code here
NSLog(#"Display messages");
//First match the user with the messageBank
PFQuery *messageBankQuery = [PFQuery queryWithClassName:#"messageBank"];
[messageBankQuery whereKey:#"username" equalTo:[PFUser currentUser].username];
[messageBankQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if(!error) {
//first object matches
PFObject *messageBank = objects[0];
PFRelation *receivedMessages = [messageBank relationForKey:#"receivedMessages”];
PFQuery *receivedMessagesQuery = [receivedMessages query];
[receivedMessagesQuery orderByAscending:#"createdAt"];
[receivedMessagesQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if((!error) &&([objects count]>0)) {
for(PFObject *message in objects) {
UIView *content = [[[NSBundle mainBundle] loadNibNamed:#"messageView" owner:self options:nil] objectAtIndex:0];
//this doesn't have a view to add to!!!
}
[self completeOperation];
}//end if
else {
[self completeOperation]; }
}];
}
}];
}
I'm currently developing a App thats home view controller shows a display of all the users friends, their names and their profile images (if they have one), each within a cell of a UICollectionView. I am using tags to identify the UI elements within each cell and Parse as the backend. Each user and their relations are stored under the class "User" and then their profile images (if they have chosen one/taken one) are stored under another class called "UserImage". I've managed to set their usernames to the cells but having difficulty with the images. Basically each cell is downloading the entire image array, which I believe is causing the app to crash with this error. Also as soon as the user adds a friend without a profile picture the app seems to act strange..
[__NSArrayM objectAtIndex:]: index 8 beyond bounds [0 .. 1]
here is how I save the image to parse.. This is in the users profile view controller.
-(void)uploadImage {
NSData *fileData;
NSString *fileName;
NSString *fileType;
UIImage *newImage = [self scaleImage:self.image toSize:CGSizeMake(340.0,340.0)];
fileData = UIImagePNGRepresentation(newImage);
fileName = #"profileimage.png";
fileType = #"profileimage";
PFFile *file = [PFFile fileWithName:fileName data:fileData];
[file saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
PFUser *user = [PFUser currentUser];
PFObject *userImage = [PFObject objectWithClassName:#"UserImage"];
[userImage setObject:file forKey:#"file"];
[userImage setObject:fileType forKey:#"fileType"];
[userImage setObject:user forKey:#"user"];
[userImage saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (error) {
NSLog(#"Error saving image");
}
else {
NSLog(#"Image Saved");
}
}];
}];
}
I then query for the current users relations within the viewWillAppear: method of the HomeViewController.
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.navigationController.navigationBar setHidden:NO];
self.friendsRelation = [[PFUser currentUser] objectForKey:#"friendsRelation"];
self.friends = [[NSMutableArray alloc] init];
PFQuery *query = [self.friendsRelation query];
[query orderByAscending:#"username"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error) {
NSLog(#"Error %# %#", error, [error userInfo]);
}
else {
[self.friends addObjectsFromArray:objects];
[self.collectionView reloadData];
}
}];
}
Setting the amount of cells to the amount of the users friends..
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return [self.friends count];
}
And finally setting up the cells within the cellForItemAtIndexPath: method
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *identifier = #"Cell";
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
PFUser *user = [self.friends objectAtIndex:indexPath.row];
if (cell.tag == 0) {
UILabel *cellLabel = (UILabel *)[cell viewWithTag:25];
cellLabel.text = user.username;
PFImageView *homeImageView = (PFImageView *)[cell viewWithTag:50];
[homeImageView setContentMode:UIViewContentModeScaleAspectFill];
homeImageView.clipsToBounds = YES;
homeImageView.layer.cornerRadius = 7;
self.friendImages = [[NSMutableArray alloc] init];
PFQuery *imageQuery = [PFQuery queryWithClassName:#"UserImage"];
[imageQuery whereKey:#"user" containedIn:self.friends];
[imageQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
//need a statement that defines whether a friend has an image or not, if they do then load that image into their cell, if not then set default image
[self.friendImages addObjectsFromArray:objects];
PFObject *imageObject = [self.friendImages objectAtIndex:indexPath.row];
PFFile *imageFile = [imageObject objectForKey:#"file"];
homeImageView.file = imageFile;
[homeImageView loadInBackground];
NSLog(#"Retrieved %d images", [self.friendImages count]);
}
else {
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
return cell;
}
Any help would be appreciated! keep in mind I'm only a couple of weeks into learning iOS..