i'm a new iOS developer; i have an application with parse and dynamic cell but when i run the app i find that the app is crashed due to the reason on the title my code as the following
- (UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index reusingView:(UIView *)view
{
myArray = [[NSMutableArray alloc] init];
//create new view if no view is available for recycling
// view = [[[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 250.0f, 300.0f)] autorelease];
FXImageView *imageView = [[[FXImageView alloc] initWithFrame:CGRectMake(0, 0, 250.0f, 350.0f)] autorelease];
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.asynchronous = YES;
// imageView.reflectionScale = 0.5f;
// imageView.reflectionAlpha = 0.25f;
// imageView.reflectionGap = 10.0f;
imageView.shadowOffset = CGSizeMake(0.0f, 2.0f);
imageView.shadowBlur = 5.0f;
imageView.cornerRadius = 10.0f;
view = imageView;
[ProgressHUD dismiss];
NSString *string1 = [[NSUserDefaults standardUserDefaults] stringForKey:#"Class"];
PFQuery *query = [PFQuery queryWithClassName:[NSString stringWithFormat:#"%#",string1]];
query.cachePolicy = kPFCachePolicyNetworkElseCache;
//show loader view
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
myArray = [[NSMutableArray alloc] initWithArray:objects];
PFObject *object = [myArray objectAtIndex:index];
[file getDataInBackgroundWithBlock:^(NSData *data1, NSError *error) {
if (!error) {
((UIImageView *)view).image = [UIImage imageWithData:data1];
//[HUD hideUIBlockingIndicator];
}
}];
}
}];
return view;
}
i use for first screen UICollectionView with dynamic data from parse as the following code
pragma collectionView delegate
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"cell";
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
CALayer *layer = cell.layer;
[layer setCornerRadius:8.0f];
[layer setMasksToBounds:YES];
// [layer setBorderWidth:1.0f];
// layer.backgroundColor = [UIColor whiteColor].CGColor;
//can you click
PFObject *imageObject = [myArray objectAtIndex:indexPath.item];
PFFile *imageFile = [imageObject objectForKey:#"image"];
NSString *name = [imageObject objectForKey:#"name"];
[imageFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if (!error) {
UIImageView *imageView = (UIImageView *)[cell viewWithTag:100];
imageView.image = [UIImage imageWithData:data];
UILabel *title2 = (UILabel *)[cell viewWithTag:200];
title2.text = [NSString stringWithFormat:#"%#",name];
title2.font = [UIFont fontWithName:#"GESSTextMedium-Medium" size:12];
}
}];
return cell;
}
i need some help to know where is the error;
every time i receive this error on console [__NSArrayM objectAtIndex:]: index 2 beyond bounds [0 .. 1]
There is not enough information. We even don't know the exact line for this crash.
What is the actual number of objects in myArray?
What you return on collectionView:numberOfItemsInSection:
and so on..
Imho, the easiest solution would be debugging this crash. And finding out why index is larger then objectAtIndex: expected. Try this:
1) Open "Breakpoint navigator"
2) tap '+' button and choose "Add Exception Breakpoint" option
Now app will use this breakpoint on any exception while debugging.
Salutations and welcomes, new developer. The first thing you want to find out is where that exception is happening. To do that, you're going to need to turn on the "exception breakpoint".
The exact way you do that varies by Xcode version (thanks Apple). Assuming that you are using Xcode 6, there's a video here that explains it.
I think it is quite likely that your carousel is miss-reporting the number of items it has. Or for some other reason you are trying to get a carousel item that does not exist… perhaps the carousel expects a nil when it queries with an index of a cell outside of the existing range, but you're assuming the index is valid and hitting an array bounds exception. At a wild guess, possibly the error is with the lines here:
…
myArray = [[NSMutableArray alloc] initWithArray:objects];
PFObject *object = [myArray objectAtIndex:index];
…
I would guess that section is not a valid index in to myArray.
(By the way – myArray is a mutable copy of the objects array. Why are you doing this? You don't make any changes to myArray, so it seems unnecessary.)
You probably have a method collectionView: numberOfItemsInSection: in your collection view delegate. Or if you don't, you probably need one. What's the code in that at the moment?
Your problem is in this line: PFObject *object = [myArray objectAtIndex:index];
Your index for this is 2 but you only have 2 objects in your array. Since the max index of your array is 1 (0..1), it crashes. I suggest seeing where that method is called and how you are getting an index that is out of range.
It is probably one of these two lines:
PFObject *object = [myArray objectAtIndex:index];
or
PFObject *imageObject = [myArray objectAtIndex:indexPath.item];
The problem is that index (or indexPath.item in the second case) contains the value 2, yet myArray is of size 2 (therefore the only valid indexes are 0 and 1).
finally i find the problem where; i must define the array for iCarousel numberOfItems so the code will be as the following
- (NSUInteger)numberOfItemsInCarousel:(iCarousel *)carousel
{
//return the total number of items in the carousel
return ([myArray count]);
return ([titleArray count]);
return ([priceArray count]);
return ([sapArray count]);
}
so i escape from the index problem
thanks for all sharing with me
Please check your numberOfRowsInSection method and array count you are using.
Related
I'm using UITableViewController for displaying data from Parse. It runs perfectly on my Xcode Simulator as i think there's no latency in network. But whenever i'm uploading the code to AppStore for Testing. The very first time i run the app it has to load a couple of restaurant's from Parse and display in UITableViewController. Upon clicking a row the first rows data is being loaded into the 3rd row and 4th row data loading in 6th row data irregularly. Why is the data being loaded very unevenly ? Here's my
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *cellIdentifier = #"restaurantIdentifier";
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
PFObject *tempObject = [self.objectArray objectAtIndex:indexPath.row];
PFFile *imageFile = [tempObject objectForKey:#"RestaurantIcon"];
PFImageView *imageView = [[PFImageView alloc] init];
imageView.file = imageFile;
[imageView loadInBackground:^(UIImage *img,NSError *error){
if(!error){
cell.imageCell.image = imageView.image;
}
}];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.imageView.contentMode = UIViewContentModeScaleAspectFit;
cell.imageView.layer.masksToBounds = YES;
cell.imageView.layer.cornerRadius = 4;
cell.imageView.frame = self.view.bounds;
cell.cellLabel.text = [tempObject objectForKey:#"RestaurantName"];
[self.hotelNamesArray addObject:[tempObject objectForKey:#"RestaurantName"]];
cell.cellLabel.lineBreakMode = NSLineBreakByWordWrapping;
return cell;
}
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
_restaurantName = [self.hotelNamesArray objectAtIndex:indexPath.row];
self.restaurantMenuNameArray = [[NSMutableArray alloc] init];
PFQuery *query = [PFQuery queryWithClassName:[self.hotelNamesArray objectAtIndex:indexPath.row]];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
for (PFObject *obj in objects) {
if (![_restaurantMenuNameArray containsObject:[obj objectForKey:#"RestaurantMenuName"]]) {
NSLog(#"restaurantmenunames are %#",[obj objectForKey:#"RestaurantMenuName"]);
if ([obj objectForKey:#"RestaurantMenuName"] ==nil) {
[self performSegueWithIdentifier:#"restaurantDetail" sender:self];
return;
}else {
[_restaurantMenuNameArray addObject: [obj objectForKey:#"RestaurantMenuName"]];
}
}
}
}else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
[self.tableView reloadData];
NSLog(#"restaurantMenuNames is %#",_restaurantMenuNameArray);
[self performSegueWithIdentifier:#"restaurantDetail" sender:self];
}];
}
Thanks in advance.
If you mean the images get in the wrong cell, you have to consider that cells are recycled when you scroll, and that if the image loading takes a bit too long, you may get the result after the cell has been reused.
You need to check that the cell is still for the item/row you want (you could store the row in the cell's tag and check it before setting the image in the completion handler, for instance).
If it's other data that is mixed up, then you'll need to show us the code that loads that data.
I have created a UITableView which contains cells that display Users. Each cell is added within this method -tableView:cellForRowAtIndexPath:. And each cell has content linked to the specific user, like an UIImageView and UILabel.
The UITableView works properly as long as there is no more than 9-10 cells displaying. But when the number of cells become higher, so the user has to scroll down to view them all, that's when the odd behavior begins. Content from the first, second, third and so on, is added to cell number eleven, twelve, thirteen and so on. And when the user then scroll up, the content that is supposed to be on number 11, 12, 13 is now in the first, second and third cell...
I hope someone understands my problem, and know what is wrong here..
Here is the code I user to add cells.. Ignore the parse stuff though, I dont think it is relevant
- (UITableViewCell *)tableView:(UITableView *)tableview cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *simpleTableIdentifier = #"SimpleTableCell";
UITableViewCell *cell = [tableview dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
if (tableview == commentViewTableView) {
//Ignore this
} else if (tableview == tableView) {
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(5, 5, 34, 34)];
imageView.contentMode = UIViewContentModeScaleAspectFill;
imageView.clipsToBounds = YES;
[cell addSubview:imageView];
UILabel *usernameLabel = [[UILabel alloc] initWithFrame:CGRectMake(44, 0, 160, 44)];
usernameLabel.textAlignment = NSTextAlignmentLeft;
usernameLabel.font = [UIFont systemFontOfSize:17];
usernameLabel.backgroundColor = [UIColor clearColor];
[cell addSubview:usernameLabel];
UIImageView *hitImageView = [[UIImageView alloc] initWithFrame:CGRectMake(245, 9.5, 25, 25)];
hitImageView.contentMode = UIViewContentModeScaleAspectFill;
hitImageView.clipsToBounds = YES;
hitImageView.image = [UIImage imageNamed:#"hit.png"];
[cell addSubview:hitImageView];
NSString *key = //Code to retrieve userKey
PFQuery *query = [PFUser query];
[query whereKey:#"objectId" equalTo:key];
[query getFirstObjectInBackgroundWithBlock:^(PFObject *object, NSError *error) {
if (!error) {
[[object objectForKey:#"image1"] getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if (!error) {
NSString *ageString = [[NSString alloc] initWithFormat:#"%li", (long)age];
imageView.image = [UIImage imageWithData:data];
usernameLabel.text = [NSString stringWithFormat:#"%#, %#", [object objectForKey:#"username"], ageString];
}
}];
}
}];
}
}
return cell;
}
I solved my problem by doing changing the cell identifier to be unique. I don't know if this actually is the way to do it, or if it is good practice, but when I did it solved my problem. So it would be good with some feedback to know if this will cause any other problems I'm might be missing?
NSString *identifier = [NSString stringWithFormat:#"Cell%li", indexPath.row];
UITableViewCell *cell = [tableview dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
//My code..
}
Change your code like this:
- (UITableViewCell *)tableView:(UITableView *)tableview cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *simpleTableIdentifier = #"SimpleTableCell";
UITableViewCell *cell = [tableview dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
} // CLOSED PARANTHESES HERE!!!!
if (tableview == commentViewTableView) {
//Ignore this
} else if (tableview == tableView) {
// ... rest of your code here
}
}
There are a couple problems with the code. One is that special care must be taken with asynch calls inside the cellForRowAtIndex: datasource method. Another is that the cells are reused, so adding subviews to them each time they come into view will pile subviews upon subview.
Lets start with the asynch operation. #nburk correctly points out the issue, but its an overstatement to say you "can't do it". You could preload everything, but then user must wait for the whole table to be ready before they can see any of it. A good strategy here is lazy load.
Lazy load depends on a place to cache the loaded result. So lets make your datasource array an array of mutable dictionaries that look like this:
#{#"user": aPFUser, #"image": aUIImage };
It makes sense to prefetch the users, otherwise, you don't even know how many you have, so, in viewWillAppear:
// setup your model as #property(strong,nonatomic) NSMutableArray *users;
PFQuery *query = [PFUser query];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// build the datasource
self.users = [NSMutableArray array];
for (PFUser *user in objects) {
NSMutableDictionary *d = [NSMutableDictionary dictionaryWithDictionary:
#{ #"user": user };
];
}
[self.tableView reloadData];
}
}];
Now, in cellForRowAtIndexPath you do this:
NSMutableDictionary *userDictionary = self.users[indexPath.row];
// in the lazy pattern, if the model is initialized, we're done
// start by assuming the best
imageView.image = userDictionary[#"image"];
// but the image might be nil (it will start out that way) so, load...
PFQuery *query = [PFUser query];
[query whereKey:#"objectId" equalTo:key];
[query getFirstObjectInBackgroundWithBlock:^(PFObject *object, NSError *error) {
if (!error) {
[[object objectForKey:#"image1"] getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if (!error) {
UIImage *image = [UIImage imageWithData:data];
// this is the important part: this code doesn't run when the rest
// of the method runs. It happens later, when the request completes
// so don't assume anything about the state of the table. Instead
// treat the table like you would in other view controller methods
userDictionary[#"image"] = image;
// don't fool around with cell (it might be reused). Instead
// just tell the table to reload this row
[tableView reloadRowsAtIndexPaths:#[indexPath]
withRowAnimation:UITableViewRowAnimationAutomatic];
}
}];
}
}];
The next time that row scrolls into view, the data from the asynch request will be cached in your user dictionary.
Problem two is simpler: the code builds subviews unconditionally, even if the (reused) cell already has that subview. The answer, again, is that laziness is your friend. Try to get the subview from the cell, and only build it if you must...
// change all of your subview-building code to do this:
UIImageView *imageView = (UIImageView *)[cell viewWithTag:32];
if (!imageView) {
imageView = [[UIImageView alloc] init....
// same code as you had here, adding...
imageView.tag = 32;
}
// and so on for the cell's other subviews. be sure to advance the tag (33, 34, etc)
In sum, the cellForRowAtIndexPath has a few sections.
dequeue the cell
lazy-build subviews as above
as above: access your model and optimistically init the subviews from the model
if part of the model is missing, do an asynch call, update the model,
and reload the cell when done
I'm pretty new at this and having a go using Parse.com as the backend server. I'm building a database of vegetables, and want to perform a search on the list pulled from parse.com. I have it all working, except for one annoying thing...
Now, I'm using storyboards and have created a custom cell which includes a PFImage thumbnail view, a label showing the vegetable, and then another label showing the season for the vegetable.
When the viewcontroller is called, the list populates perfectly and lists the vegetables in alphabetical order. Then I drag the window down to reveal the search bar. I begin typing in a vegetable name, and as I do so the original table data rows begin disappearing (as they should), but the problem is the original table data sticks around. So, for instance, I'll type "carrot", and all the rows disappear except the top row which still holds a thumbnail of an artichoke (and the label "Artichoke" as well). But overlayed on that row is also the word "Carrots", which is another vegetable in the list. If I tap on it, it properly seques to my detail view controller showing carrots. So everything is working properly, but I can't figure out how to make it so the search results aren't being written over the top of the original data.
Here's the code portions:
- (void)viewDidLoad
{
self.tableView.backgroundColor = [UIColor clearColor];
self.tableView.backgroundView=[[UIImageView alloc] initWithImage:
[UIImage imageNamed:#"bg.jpg"]];
[super viewDidLoad];
//add the search bar
self.searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 44)];
self.tableView.tableHeaderView = self.searchBar;
self.searchController = [[UISearchDisplayController alloc] initWithSearchBar:self.searchBar contentsController:self];
self.searchController.searchResultsDataSource = self;
self.searchController.searchResultsDelegate = self;
self.searchController.delegate = self;
CGPoint offset = CGPointMake(0, self.searchBar.frame.size.height);
self.tableView.contentOffset = offset;
self.searchResults = [NSMutableArray array];
//done adding search bar
}
- (PFQuery *)queryForTable
{
PFQuery *query = [PFQuery queryWithClassName:self.parseClassName];
// If no objects are loaded in memory, we look to the cache first to fill the table
// and then subsequently do a query against the network.
/* if ([self.objects count] == 0) {
query.cachePolicy = kPFCachePolicyCacheThenNetwork;
}*/
[query orderByAscending:#"vegetable"];
return query;
}
// Override to customize the look of a cell representing an object. The default is to display
// a UITableViewCellStyleDefault style cell with the label being the first key in the object.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object
{
static NSString *simpleTableIdentifier = #"VegetableCell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
// more search stuff
if (tableView == self.tableView) {
cell.backgroundColor = cell.backgroundColor;
}
else if(tableView == self.searchDisplayController.searchResultsTableView) {
PFObject *searchedVeggie = [self.searchResults objectAtIndex:indexPath.row];
cell.textLabel.text = [searchedVeggie objectForKey:#"vegetable"];
cell.backgroundColor = [UIColor whiteColor];
tableView.rowHeight = self.tableView.rowHeight;
}
PFFile *thumbnail = [object objectForKey:#"vegetableImageFile"];
PFImageView *thumbnailImageView = (PFImageView*)[cell viewWithTag:100];
thumbnailImageView.image = [UIImage imageNamed:#"placeholder.jpg"];
thumbnailImageView.file = thumbnail;
[thumbnailImageView loadInBackground];
UILabel *vegetableName = (UILabel*) [cell viewWithTag:101];
vegetableName.text = [object objectForKey:#"vegetable"];
UILabel *vegetableSeason = (UILabel*) [cell viewWithTag:102];
vegetableSeason.text = [object objectForKey:#"vegetableSeason"];
return cell;
}
Lower in the code is my prepareForSeque code and other search methods. I know it's a little ugly with repeated code, but I've been trying all sorts of things to fix my issue and wasn't going to get around to cleaning things up until I figured out the issue. Also, I created a new column on parse.com's data browser called lowerCaseVegetable since the search is case sensitive. So the search is actually performed on that column, but is displayed using the normal "vegetable" column, which has the vegetable name capitalized.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showVegetableDetail"]) {
if (self.searchDisplayController.active) {
NSLog(#"Search Display Controller");
VeggieDetailViewController *destViewController = segue.destinationViewController;
PFObject *object = [self.searchResults objectAtIndex: self.searchDisplayController.searchResultsTableView.indexPathForSelectedRow.row];
Vegetables *vegetables = [[Vegetables alloc] init];
vegetables.vegetable = [object objectForKey:#"vegetable"];
vegetables.vegetableInfo = [object objectForKey:#"vegetableInfo"];
vegetables.vegetableImageFile = [object objectForKey:#"vegetableImageFile"];
vegetables.vegetableSeason = [object objectForKey:#"vegetableSeason"];
destViewController.vegetables = vegetables;
} else {
NSLog(#"Default Display Controller");
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
VeggieDetailViewController *destViewController = segue.destinationViewController;
PFObject *object = [self.objects objectAtIndex:indexPath.row];
Vegetables *vegetables = [[Vegetables alloc] init];
vegetables.vegetable = [object objectForKey:#"vegetable"];
vegetables.vegetableInfo = [object objectForKey:#"vegetableInfo"];
vegetables.vegetableImageFile = [object objectForKey:#"vegetableImageFile"];
vegetables.vegetableSeason = [object objectForKey:#"vegetableSeason"];
destViewController.vegetables = vegetables;
}
}
}
// other search stuff
-(void)filterResults:(NSString *)searchTerm {
[self.searchResults removeAllObjects];
PFQuery *query = [PFQuery queryWithClassName: #"Vegetables"];
[query whereKeyExists:#"lowerCaseVegetable"];
[query whereKey:#"lowerCaseVegetable" containsString:searchTerm];
NSArray *results = [query findObjects];
[self.searchResults addObjectsFromArray:results];
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
[self filterResults:searchString];
return YES;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (tableView == self.tableView) {
return self.objects.count;
} else {
return self.searchResults.count;
}
}
-(void)callbackLoadObjectsFromParse:(NSArray *)result error:(NSError *)error {
if (!error) {
[self.searchResults removeAllObjects];
[self.searchResults addObjectsFromArray:result];
[self.searchDisplayController.searchResultsTableView reloadData];
} else {
// NSLog(#”Error: %# %#”, [error userInfo]);
}
}
I have a feeling I'm just making a stupid newbie mistake here, but I've only been at this since May, and specifically fighting this issue the last two weeks. I figured it was about time to ask for help.
I just implemented search in my parse app and I think I see the problem:
In your filterResults method try using findObjectsInBackgroundWithBlock instead of findObjects like this:
[query findObjectsInBackgroundWithBlock:^(NSArray *array, NSError *error){
[self.searchResults addObjectsFromArray:array];
[self.searchDisplayController.searchResultsTableView reloadData];
}];
prepareForSegue:
Vegetables *vegetables = [[Vegetables alloc] init];
vegetables.vegetable = [self.selectedObject objectForKey:#"vegetable"];
vegetables.vegetableInfo = [self.selectedObject objectForKey:#"vegetableInfo"];
vegetables.vegetableImageFile = [self.selectedObject objectForKey:#"vegetableImageFile"];
vegetables.vegetableSeason = [self.selectedObject objectForKey:#"vegetableSeason"];
destViewController.vegetables = vegetables;
* I got it figured out thanks to Paulw11 and sjeohp comments. I was using the amount of text to change the cell height and didnt correct the objectAtIndex in that method when i changed to using the array over static text. *
I have a chat app that im trying to use a tableView to show the chat interaction. Im saving the "source" and the contents into an array and trying to get the tableview to reload that anytime a message is sent or received but it crashes everytime on the reloadData call.
In the ViewDidLoad:
chatLog = [[NSMutableArray alloc]init];
and then other methods:
-(IBAction)sendMessagePressed:(UIBarButtonItem *)sender {
NSLog(#"Send Pressed");
// if the message bar isnt blank send the message
if ( ![messageInputBar.text isEqualToString:#""] ) {
NSString* text = [NSString stringWithFormat:#"You Wrote:\n%#", messageInputBar.text];
NSString* source = #"self";
NSArray* sent = [[NSArray alloc]initWithObjects:source, text, nil];
messageInputBar.text = #"";
[self CloseMessageKeys];
[chatLog addObject:sent];
// this is where it crashes. this code was working with static text before
// i implemented the mutable array
[chatTable reloadData];
NSData* messageData = [messageInputBar.text dataUsingEncoding:NSUTF8StringEncoding];
NSArray* connectedPeers = _app_Delegate.mpc_Handler.mpc_session.connectedPeers;
NSError* error;
[_app_Delegate.mpc_Handler.mpc_session sendData:messageData toPeers:connectedPeers withMode:MCSessionSendDataReliable error:&error];
if (error) {
NSLog(#"%#", [error localizedDescription]);
}
}
}
This is the TableView cellForRowAtIndexPath:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if ( [[[chatLog objectAtIndex:indexPath.row]objectAtIndex:0]isEqualToString:#"self"]) {
OutgoingTableViewCell* cell = [chatTable dequeueReusableCellWithIdentifier:#"outgoingCell" forIndexPath:indexPath];
NSString* text = [[chatLog objectAtIndex:indexPath.row]objectAtIndex:1];
cell.txtLabel.text = text;
[[cell txtLabel] setNumberOfLines:0]; // unlimited number of lines
[[cell txtLabel] setLineBreakMode: NSLineBreakByWordWrapping];
[[cell txtLabel] setFont:[UIFont systemFontOfSize: 14.0]];
cell.backgroundColor = [UIColor greenColor];
[self showTheBottom];
return cell;
} else {
IncomingTableViewCell* cell = [chatTable dequeueReusableCellWithIdentifier:#"incomingCell" forIndexPath:indexPath];
NSString* text = [[chatLog objectAtIndex:indexPath.row]objectAtIndex:1];
cell.txtLabel.text = text;
[[cell txtLabel] setNumberOfLines:0]; // unlimited number of lines
[[cell txtLabel] setLineBreakMode: NSLineBreakByWordWrapping];
[[cell txtLabel] setFont:[UIFont systemFontOfSize: 14.0]];
cell.backgroundColor = [UIColor blueColor];
[self showTheBottom];
return cell;
}
}
length is not a method on NSArray. Use [array count]
I got it figured out thanks to #Paulw11 and #sjeohp comments. I was using the amount of text to change the cell height and didnt correct the objectAtIndex in that method when i changed to using the array over static text. *
in another method I had:
NSAttributedString *aString = [NSAttributedString alloc] initWithString:[chatLog objectAtIndex:indexPath.row];
and it needed to be:
NSAttributedString *aString = [[NSAttributedString alloc] initWithString:[[chatLog objectAtIndex:indexPath.row]objectAtIndex:1]];
Thanks to #Paulw11 and #sjeohp for helping me figure out the exception breakpoint feature in Xcode
Your dequeueReusableCell code is fail. you need check if it nil then init cell. And check about numberOfRowsInSection code to return chatLog.count
I just want the user to just delete a picture by just tapping the picture using a collection view. I am doing this for a month and can't get things straight and even getting confused. My code for to do this is below. I am also getting a memory warning sometimes aswell, If i use the instruments app to look for detail the memory allocation does not get freed and just builds up until crash.
- (void)viewDidLoad
{ Trash = [NSMutableArray array];
filenames = [NSMutableArray new];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSArray *locationStrings = [[NSArray alloc]initWithObjects:#"Bottoms", #"Dress", #"Coats", #"Others", #"hats", #"Tops",nil ];
for(NSString* location in locationStrings){
NSString *fPath = [documentsDirectory stringByAppendingPathComponent:location];
NSError *error;
NSArray *directoryContent = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:fPath error:&error];
collectionTrash.delegate =self;
collectionTrash.dataSource=self;
for(NSString *str in directoryContent){
NSString *finalFilePath = [fPath stringByAppendingPathComponent:str];
[filenames addObject:finalFilePath];
}
}
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
NSLog(#"j");
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return [filenames count];
NSLog(#"b");
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"ReuseID";
TrashCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
UIImageView *imageInCell = (UIImageView*)[cell viewWithTag:1];
NSString *cacheKey = filenames[indexPath.item];
imageInCell.image = [self.imageCache objectForKey:cacheKey];
if (imageInCell.image == nil) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
UIImage *image = [UIImage imageWithContentsOfFile:filenames[indexPath.item]];
if (image) {
[self.imageCache setObject:image forKey:cacheKey];
dispatch_async(dispatch_get_main_queue(), ^{
TrashCell *updateCell = (id)[collectionView cellForItemAtIndexPath:indexPath];
UIImageView *imageInCell = (UIImageView*)[updateCell viewWithTag:1];
imageInCell.image = image;
});
}
});
}
return cell;
}
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
NSLog(#"s:%d", [Trash count]);
NSString *trashBin = [Trash objectAtIndex:indexPath.row];
NSLog(#"k%#l",trashBin);
[filenames removeObjectAtIndex:indexPath.row];
[Trash removeObjectAtIndex:indexPath.row];
[self deleteMyFiles:trashBin];
[collectionView deleteItemsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil]];
}
NSString *myFileName;
-(void) deleteMyFiles:(NSString*)filePath {
NSError *error;
if([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
[[NSFileManager defaultManager] removeItemAtPath:filePath error:&error];
} else {
NSLog(#"%#",filePath);
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
[self.imageCache removeAllObjects];
}
When I try to tap a log comes out saying below.
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array'
*** First throw call stack:
(0x30afbe83 0x3ae5c6c7 0x30a31d95 0x638e9 0x3349d76f 0x3349d495 0x33406ea3 0x33406ea3 0x332781a1 0x332af9fd 0x332af3ab 0x33284d79 0x33283569 0x30ac6f1f 0x30ac63e7 0x30ac4bd7 0x30a2f471 0x30a2f253 0x357632eb 0x332e4845 0x628a5 0x3b355ab7)
libc++abi.dylib: terminating with uncaught exception of type NSException
Your Trash array not content any objects.
And you are trying to access object from Trash array
NSString *trashBin = [Trash objectAtIndex:indexPath.row];
Which is the cause of crash.
Note: object name should start with small letters.
In your code, Trash = [NSMutableArray array]; will be autoreleased at some time, so when you access it in '-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath', it has been released. If you are sure there is reason to use this variable instead of using only filenames, you can do this Trash = [[NSMutableArray array] retain]; or Trash = [[NSMutableArray alloc] init]; in your '- (void)viewDidLoad'.
It is not clear what you are trying to do. The notion of "Trash" suggests you are trying to implement a two-stage delete: put items in the trash and at some later time, empty the trash (delete them for good when the user selects an "Empty the Trash" button). But your post and your code suggest a single-stage delete (the user selects to delete with no chance to undo).
Your collectionView:didSelectItemAtIndexPath: delegate method looks particularly confused. As Bhumeshwer correctly points out, your Trash is empty and trying to access any index is causing your crash. No where in this code are you putting anything in Trash But, by simply removing that line of code, I don't think the method will do what you want.
If you are implementing a two-stage delete, I think you simply want to remove the string from filenames and add it to Trash. Don't remove the object from Trash and don't delete files in Trash. Somewhere else (like when the "Empty the Trash" button is selected), call deleteMyFiles to empty the trash.
If you are implementing a single-stage delete, get rid to Trash all together: don't allocate it in viewDidLoad and don't empty it in didSelectItemAtIndexPath. Simply, remove the object from filenames AND update the imageInCell!
Suggestions:
move
collectionTrash.delegate =self;
collectionTrash.dataSource=self;
to wherever collectionTrash is being created and initialized. Inside viewDidLoad and inside the for loop, it is out of context. Your mixing unrelated lines of code making your code unorganized and confusing. At least, move it out of the for loop.
think model-view-controller. What's the model here? Is it filenames or Trash? Is the CollectionView a view of filenames or Trash? What is collectionTrash?
Trash should be trash (as Bhumeshwer points out);
what is NSString *myFileName; and what's it doing there?
don't forget to manage your imageCache. You put images in but don't take them out. When you remove a file from filenames, remove the image from imageCache.
I could go on, but will stop here. Good luck.