Why do I have a memory leaking with ARC enabled(highlighted in bold)?
I have CustomCell.m
+(CustomCell*)cell
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
NSArray *nib =[[NSBundle mainBundle] loadNibNamed:#"CustomCell_iPhone" owner:self options:nil];
return [nib objectAtIndex:0];
} else {
NSArray *nib =[[NSBundle mainBundle] loadNibNamed:#"CustomCell_iPad" owner:self options:nil]; **//leaking 100%**
return [nib objectAtIndex:0];
}
}
In my tableview conteroller:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
cell=[CustomCell cell]; **// 100% leaking**
...
}
So, two things. One, I gather you're creating this cell in a .xib file. Set the reuse identifier on the cell in IB. Then, instead of this CustomCell class method, unload the nib in tableView:cellForRowAtIndexPath:, like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Assuming you set a reuse identifier "cellId" in the nib for your table view cell...
MyCell *cell = (MyCell *)[tableView dequeueReusableCellWithIdentifier:#"cellId"];
if (!cell) {
// If you didn't get a valid cell reference back, unload a cell from the nib
NSArray *nibArray = [[NSBundle mainBundle] loadNibNamed:#"MyCell" owner:nil options:nil];
for (id obj in nibArray) {
if ([obj isMemberOfClass:[MyCell class]]) {
// Assign cell to obj, and add a target action for the checkmark
cell = (MyCell *)obj;
break;
}
}
}
return cell;
}
The second thing is that by trying to dequeue a reusable cell first, you will get much much better performance.
Related
I am stuck on how to use groupBy with MagicalRecord.
I have a list of countries with venues
Country -<< Venues
I need to group all the venues by the country and sort the countries by name.
But I am not sure how to do this with MagicalRecord.
I have tried to use a NSFetchedController but sometimes it crashes saying that the array is nil or 0 length.
Other times, it only ever sees 1 category when there are multiple.
Finally, I am not sure how to execute the fetch on an entity.
ie;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
_objects = [NSMutableArray array];
self.fetchedResultsController = [self fetchedResultsController];
[Venue performFetch:self.fetchedResultsController];
// At this point how do I make the Venue findAllSortedBy work on the performFetch?
_objects = [NSMutableArray arrayWithArray:[Venue findAllSortedBy:#"name" ascending:YES inContext:[NSManagedObjectContext defaultContext]]];
self.title = #"Venues";
}
- (NSFetchedResultsController *)fetchedResultsController {
if (!fetchedResultsController) {
fetchedResultsController = [Venue fetchAllSortedBy:#"name"
ascending:YES
withPredicate:nil
groupBy:#"country"
delegate:self];
}
return fetchedResultsController;
}
-(NSString*)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
NSLog(#"Section = %d", section);
id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
NSLog(#"sectionInfo = %#", sectionInfo);
return #"Header";
}
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tv dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
Venue *v = [_objects objectAtIndex:indexPath.row];
cell.textLabel.text = v.name;
}
I am not sure if I am doing this right.
The above will put everything in 1 country (when there are multiple) and the log will report;
CoreData: error: (NSFetchedResultsController) A section returned nil value for section
name key path 'country'. Objects will be placed in unnamed section
It seems not to see the different countries and I do not think I've done the GroupBy command correctly.
Thus, how do I do a GroupBy command with MagicalRecord?
Many thanks.
self.fetchedVenues = [Venue MR_fetchAllGroupedBy:#"country" withPredicate:nil sortedBy:#"name" ascending:YES];
This error is telling you that of all your Venue objects, there is at least one in your result set that does not have a value for "country". You need to verify that you are indeed filling in this field and saving it properly prior to fetching.
And FYI, in your viewDidLoad method, you don't need all that code. Simply do something like:
- (void) viewDidLoad;
{
[super viewDidLoad];
self.fetchedVenues = [Venue fetchAllSortedBy:#"name" ascending:YES withPredicate:nil groupBy:#"country" delegate:self];
}
fetchAllSortedBy... will perform the fetch for you, and log errors, etc. That is the point of a helper framework like MagicalRecord.
I need some help searching / filtering a Core data entity. The results array returns Null..
I have a root view with a search bar, controller and tableview. This view shows normally.
I'm calling the UISearchBarDelegate and the UISearchDisplayDelegate.
I have a mutable array (searchResults).
My search code is as follows:
-(void) filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
NSLog(#"%s", __FUNCTION__);
[self.searchResults removeAllObjects];
for (Entity *ent in [self.fetchedResultsController fetchedObjects])
{
if ([scope isEqualToString:#"All"] || [ent.title isEqualToString:scope])
{
NSRange range = [ent.title rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (range.location != NSNotFound)
{
NSLog(#"Adding title '%#' to searchResults as it contains '%#'", ent.title, searchText);
[self.searchResults addObject:ent];
}
}
}
NSLog(#"The searchResults array contains '%#'", searchResults); <<<< RETURNS NULL
}
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString scope:#"All"];
return YES;
}
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption
{
[self filterContentForSearchText:[self.searchDisplayController.searchBar text ]scope:#"All"];
return YES;
}
and the cell config code is:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"MyVeryOwnCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
Entity *entity = nil;
if (tableView == self.searchDisplayController.searchResultsTableView)
{
//NSLog(#"Configuring cell to show search results");
entity = [self.searchResults objectAtIndex:indexPath.row];
}
else
{
//NSLog(#"Configuring cell to show normal data");
entity = [self.fetchedResultsController objectAtIndexPath:indexPath];
}
cell.textLabel.text = entity.title;
return cell;
}
I must be doing something dumb as the searchResults array appears to be null. I would appreciate any advice.
You just forgot to alloc/init the searchResults array.
;-)
I need to implement two different index paths on my tableview in cellForRow at index path... One with data from my fetched results controller and another for simple text.
What is the best way to go about this.
Im not exactly sure what your asking, but it sounds like you want a table with one section containing results from an NSFetchedResultController, and another section with data from some other source. This is easy to do. If your data can doesn't need to be in multiple sections then it's very easy, just get data from fetchedResultController for section 0, and something else for section 1.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
if(section == 0){
id sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
}else{
return self.someArray.Count;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
if(indexpath.section == 0){
static NSString *CellIdentifier = #"data cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
NSObject *foo = [self.fetchedResultController objectAtIndexPath:indexPath];
//configure cell
return cell;
}else{
static NSString *CellIdentifier = #"some other cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
//configure cell
return cell;
}
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Set up the cell...
NSUInteger row = [indexPath row];{
cell.text = [capitulosArray objectAtIndex:row];
return cell;
}
NSUInteger row = [indexPath row];{
cell.text = [capitulos2Array objectAtIndex:row];
return cell;
}
}
Im here to learn
You seem to think that NSUInteger row = [indexPath row];{ ... } is something like C#'s using. It's not, it's just like the similar construct in C. So you are declaring the local variable "row" twice, and the compiler is warning you about it.
As for the warning that "setText" is deprecated, that's because it is. See the documentation. You'll most likely want to use cell.textLabel.text instead.
I have an app that has a tab bar, each tab contains a separate table. The first table uses core data to persist its entries and checkmarks. The second table on the second tab uses an NSMutableArray to populate it (I would use core data but I would have to pre populate it and this table does not allow that) I would like to persist check marks the same way I do in the first table with core data but something is wrong. The code looks like this:
-(void)viewDidLoad {
[super viewDidLoad];
airport = [[NSMutableArray alloc] init];
[airport addObject:#"Passport"];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [airport count];
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Set up the cell...
NSString *cellValue = [airport objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
//[cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
NSManagedObject *item = [[self fetchedResultsController] objectAtIndexPath:indexPath];
cell.textLabel.text = [item valueForKey:#"name"]; //CHANGED TO DETAIL
if ([[item valueForKey:#"check"] boolValue]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSManagedObject *selectedObject = [self.fetchedResultsController objectAtIndexPath:indexPath];
if ([[selectedObject valueForKey:#"check"] boolValue]) {
[selectedObject setValue:[NSNumber numberWithBool:NO] forKey:#"check"];
} else {
[selectedObject setValue:[NSNumber numberWithBool:YES] forKey:#"check"];
}
UITableViewCell *thisCell = [tableView cellForRowAtIndexPath:indexPath];
if (thisCell.accessoryType == UITableViewCellAccessoryNone) {
thisCell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
thisCell.accessoryType = UITableViewCellAccessoryNone;
}
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
I believe the line cell.textLabel.text = [item valueForKey#"name"];
is whats causing it. All that I would like for this to do is have the table populated from the array and check marks persisted. Any help is GREATLY appreciated. Thanks in advance.
This line is replacing the cell text:
cell.textLabel.text = [item valueForKey:#"name"];
that was initially assigned by these lines:
NSString *cellValue = [airport objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
Why are your using the "name" property of "item"?