sudden EXC_BAD_ACCESS at - (NSString *)tableView: titleForHeaderInSection: - ios

I think just showing my whole code is better than my explanation.. actually I'm not good at expressing something in English.X(
this code is .h file for .m file below.
#import <UIKit/UIKit.h>
#define kImageValueTag 0
#define kNameValueTag 1
#define kSubtitleValueTag 2
#define kMemoValueTag 3
#class PhonebookDetailedViewController;
#interface PhonebookViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
{
UITableViewCell *tvCell;
UITableView *tableView;
UISearchBar *searchBar;
NSString *fullName;
NSMutableDictionary *names, *pictures;
NSArray *keys, *sortedKeys, *sortedAllValues;
PhonebookDetailedViewController *childController;
}
#property (nonatomic, retain) IBOutlet UITableViewCell *tvCell;
#property (nonatomic, retain) IBOutlet UISearchBar *searchBar;
#property (nonatomic, retain) IBOutlet UITableView *tableView;
#property (nonatomic, retain) UIImage *phoneImage;
#property (nonatomic, retain) NSString *fullName;
#property (nonatomic, retain) NSMutableDictionary *names;
#property (nonatomic, retain) NSMutableDictionary *pictures;
#property (nonatomic, retain) NSArray *keys;
#property (nonatomic, retain) NSArray *sortedKeys;
#property (nonatomic, retain) NSArray *sortedAllValues;
#end
this code is for the .m file that implement showing a table. When I try to scroll the table down, the error named EXC_BAD_ACCESS is suddenly called at - (NSString *)tableView: titleForHeaderInSection: method. I guess sortedKeys releases at somewhere because I can do [sortedKeys count] before error, but cannot when error comes. I don't know where it releases and why it releases, however. Please show your ideas to me. Any ideas are okay. Thank you in advance.
#import "PhonebookViewController.h"
#import "PhonebookDetailedViewController.h"
#import "NSString-SortForIndex.h"
#implementation PhonebookViewController
#synthesize tvCell;
#synthesize searchBar;
#synthesize tableView;
#synthesize phoneImage;
#synthesize fullName;
#synthesize names, pictures;
#synthesize keys, sortedAllValues, sortedKeys;
//- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
//{
// self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
// if (self) {
// // Custom initialization
// }
// return self;
//}
//- (void)didReceiveMemoryWarning
//{
// // Releases the view if it doesn't have a superview.
// [super didReceiveMemoryWarning];
//
// // Release any cached data, images, etc that aren't in use.
//}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect bounds = self.tableView.bounds;
bounds.origin.y = bounds.origin.y + searchBar.bounds.size.height;
self.tableView.bounds = bounds;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *nameFilePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"nameContacts.dict"];
NSString *pictureFilePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"imageContacts.dict"];
self.names = (NSMutableDictionary *)[NSKeyedUnarchiver unarchiveObjectWithFile:nameFilePath];
self.pictures = (NSMutableDictionary *)[NSKeyedUnarchiver unarchiveObjectWithFile:pictureFilePath];
self.keys = [self.names allKeys];
sortedKeys = [self.keys sortedArrayUsingSelector:#selector(sortForIndex:)];
sortedAllValues = [[NSArray alloc] init];
for (NSString *sortedKey in sortedKeys)
{
NSArray *selectedValues = [self.names valueForKey:sortedKey];
for (NSString *selectedValue in selectedValues)
sortedAllValues = [sortedAllValues arrayByAddingObject:selectedValue];
}
// Do any additional setup after loading the view from its nib.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
self.tableView = nil;
self.searchBar = nil;
self.tvCell = nil;
self.fullName = nil;
self.names = nil;
self.pictures = nil;
self.keys = nil;
self.sortedKeys = nil;
self.sortedAllValues = nil;
}
- (void)dealloc
{
[tableView release];
[searchBar release];
[tvCell release];
[fullName release];
[names release];
[pictures release];
[keys release];
[sortedKeys release];
[sortedAllValues release];
[super dealloc];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - Table Data Source Methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [sortedKeys count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSString *key = [sortedKeys objectAtIndex:section];
NSArray *nameSection = [names objectForKey:key];
return [nameSection count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CustomCellIdentifier = #"CustomCellIdentifier";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CustomCellIdentifier];
if ( cell == nil )
{
NSArray *nib = [[NSBundle mainBundle]
loadNibNamed:#"CustomPhonebookCell"
owner:self
options:nil];
if (nib.count > 0)
{
cell = self.tvCell;
} else
{
NSLog(#"Failed to load CustomPhonebookCell nib file!");
}
}
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
NSUInteger row = [indexPath row];
NSUInteger section = [indexPath section];
NSString *foundKey = [sortedKeys objectAtIndex:section];
NSArray *nameSection = [self.names objectForKey:foundKey];
UILabel *nameLabel = (UILabel *)[cell viewWithTag:kNameValueTag];
nameLabel.text = [nameSection objectAtIndex:row];
return cell;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
NSString *key = [sortedKeys objectAtIndex:section]; // EXC_BAD_ACCESS error at here
return key;
}

sortedKeys is not properly retained. When you set it use self.
self.sortedKeys = [self.keys sortedArrayUsingSelector:#selector(sortForIndex:)];

Related

Table View Cell - UITableView - Cannot show multiple rows in detailed view

I am using Tableview to display Name from recipes Array which works great and displays all name in table view from recipes Array. When i tap on one of the recipe it displays the name on detailed view.
What i am stuck of is, how to display other fields in the detailed view.I have an Array ( array name: ingredients ) which has contents of that specific recipe, example ingredients.
I tried with
cell.textLabel.text = [ingredients objectAtIndex:indexPath.row];
RecipeDetailViewController.h
#import <UIKit/UIKit.h>
#interface RecipeDetailViewController : UIViewController
#property (nonatomic, strong) IBOutlet UILabel *recipeLabel;
#property (nonatomic, strong) NSString *recipeName;
#property (strong, nonatomic) IBOutlet UILabel *recipeCountry;
#property (nonatomic, strong) NSString *recipeCountryName;
#end
but it doesn't show anything in RecipeBookViewController.m
Here is my Original code
#import "RecipeBookViewController.h"
#import "RecipeDetailViewController.h"
#interface RecipeBookViewController ()
#end
#implementation RecipeBookViewController {
NSArray *recipes;
}
#synthesize tableView;
- (void)viewDidLoad
{
[super viewDidLoad];
NSData *allCourseData=[[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:#"http://api.kivaws.org/v1/loans/search.json?status=fundraising"]];
NSError *error;
NSMutableDictionary *JsonObject = [NSJSONSerialization
JSONObjectWithData:allCourseData options:NSJSONReadingMutableContainers
error:&error];
NSArray *loans = JsonObject[#"loans"];
// Create a new loans array for store the new items
NSMutableArray *newLoans = [NSMutableArray array];
NSMutableArray *arrCountry = [NSMutableArray array];
for (NSDictionary *loan in loans) {
NSNumber *ident = loan[#"id"];
NSString *name = loan[#"name"];
NSDictionary *description = loan[#"description"];
NSDictionary *location = loan[#"location"];
NSString *country = location[#"country"];
NSString *status = loan[#"status"];
NSDictionary *geo = location[#"geo"];
NSString *geoprint = geo[#"pairs"];
[newLoans addObject:name];
[arrCountry addObject:country];
}
recipes=newLoans;
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [recipes count];
}
//Display Name in Detail View
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"RecipeCell";
//Displays name
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
cell.textLabel.text = [recipes objectAtIndex:indexPath.row];
return cell;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showRecipeDetail"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
RecipeDetailViewController *destViewController = segue.destinationViewController;
destViewController.recipeName = [recipes objectAtIndex:indexPath.row];
}
}
#end
RecipeDetailViewController.m
#import "RecipeDetailViewController.h"
#interface RecipeDetailViewController ()
#end
#implementation RecipeDetailViewController
#synthesize recipeLabel;
#synthesize recipeName;
#synthesize recipeCountry;
#synthesize recipeCountryName;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Set the Label text with the selected recipe
recipeLabel.text = recipeName;
recipeCountry.text=recipeCountryName;
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
Here are the screenshots of both Views
Changes in your loop;
for (NSDictionary *loan in loans) {
NSNumber *ident = loan[#"id"];
NSString *name = loan[#"name"];
NSDictionary *description = loan[#"description"];
NSDictionary *location = loan[#"location"];
NSString *country = location[#"country"];
NSString *status = loan[#"status"];
NSDictionary *geo = location[#"geo"];
NSString *geoprint = geo[#"pairs"];
[newLoans addObject:#[
#"name":name,
#"description":description,
#"country ":country
]]; // Same way add all keys
//Or
/*
NSMutableDictionary* dicData = [NSMutableDictionary dictionary];
newLoans[#"name"] = name;
newLoans[#"description"] = description;
newLoans[#"country"] = country;
[newLoans addObject:dicData];
*/
}
recipes=newLoans;
Change when retrieving;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
. . .
NSDictionary * dict = [recipes objectAtIndex:indexPath.row];
cell.textLabel.text = dict[#"name"];
return cell;
}
Same way pass the complete dictionary to the RecipeDetailViewController and show other information there.

"Terminating app due to uncaught exception 'NSInvalidArgumentException'"

I am creating an iOS app. Since I am a beginner, I started with checking out some tutorials.
I started with creating an app with a Table View. The cells are dynamically filled through a database connection. This works fine.
However now I'm trying to define a push segue that opens a detail view for the cells. These also have to become filled dynamically with data. To achieve this, I started going through this tutorial and got it working up to "Passing Data Using Segue". In that step, you have to assign an identifier to your segue and fill in the prepareForSegue:sender: method.
I believe the implementation of my method causes the above error, because it isn't doing what it's supposed to. Looking up the error did not provide me with (understandable) answers since I fail to see how this problem has arisen.
Could someone please take a look at my code? Thanks in advance.
Main.storyboard:
In case you might be wondering, I did add an identifier to my segue, named showEventDetails.
EventsTableViewController.h
#import <UIKit/UIKit.h>
#import <sqlite3.h>
#interface EventsTableViewController : UITableViewController {
NSMutableArray *EventsArray;
sqlite3 *db;
}
#property (nonatomic, retain) NSMutableArray *EventsArray;
#property (nonatomic, strong) IBOutlet UITableView *eventTable;
-(NSMutableArray *) EventList;
#end
EventsTableViewController.m
#import "EventsTableViewController.h"
#import "TableCellViewController.h"
#import "Event.h"
#import <sqlite3.h>
#implementation EventsTableViewController
#synthesize EventsArray;
#synthesize eventTable;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[self EventList];
[super viewDidLoad];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (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];
}
- (NSMutableArray *) EventList
{
EventsArray = [[NSMutableArray alloc] initWithCapacity:10];
#try {
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSString *dbPath = [[[NSBundle mainBundle] resourcePath]stringByAppendingPathComponent:#"eventsDb.sqlite"];
BOOL success = [fileMgr fileExistsAtPath:dbPath];
if(!success) {
NSLog(#"Cannot locate database file '%#'.", dbPath);
}
if (!(sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK)) {
NSLog(#"An error has occured: %s", sqlite3_errmsg(db));
}
const char *sql = "SELECT * FROM events";
sqlite3_stmt *sqlStatement;
if(sqlite3_prepare(db, sql, -1, &sqlStatement, NULL) != SQLITE_OK) {
NSLog(#"Problem with prepare statement: %s", sqlite3_errmsg(db));
}
else {
while (sqlite3_step(sqlStatement) == SQLITE_ROW) {
Event *event = [[Event alloc] init];
event.name = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement, 1)];
event.date = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement, 2)];
event.starttime = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement, 3)];
event.endtime = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement, 4)];
event.location = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement, 5)];
event.description = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement, 6)];
event.favourite = sqlite3_column_int(sqlStatement, 7);
[EventsArray addObject:event];
event = nil;
}
}
sqlite3_finalize(sqlStatement);
}
#catch (NSException *exception) {
NSLog(#"Problem with prepare statement: %s", sqlite3_errmsg(db));
}
#finally {
sqlite3_close(db);
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"EventCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
int rowCount = indexPath.row;
Event *event = [self.EventsArray objectAtIndex:rowCount];
cell.textLabel.text = event.name;
cell.detailTextLabel.text= event.description;
return cell;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showEventDetails"]) {
NSIndexPath *indexPath = [self.eventTable indexPathForSelectedRow];
TableCellViewController *destViewController = segue.destinationViewController;
destViewController.eventName = [EventsArray objectAtIndex:indexPath.row];
}
}
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
}
#end
TableCellViewController.h
#import <UIKit/UIKit.h>
#interface TableCellViewController : UIViewController
#property(nonatomic, copy) NSString *eventName;
#property(nonatomic, strong) IBOutlet UILabel * eventNameLabel;
#property(nonatomic, copy) NSString *eventDate;
#property(nonatomic, strong) IBOutlet UILabel * eventDateLabel;
#property(nonatomic, copy) NSString *eventStarttime;
#property(nonatomic, strong) IBOutlet UILabel * eventStarttimeLabel;
#property(nonatomic, copy) NSString *eventEndtime;
#property(nonatomic, strong) IBOutlet UILabel * eventEndtimeLabel;
#property(nonatomic, copy) NSString *eventLocation;
#property(nonatomic, strong) IBOutlet UILabel * eventLocationLabel;
#property(nonatomic, copy) NSString *eventDescription;
#property(nonatomic, strong) IBOutlet UILabel * eventDescriptionLabel;
#property(nonatomic, assign) NSInteger eventFavourite;
#property(nonatomic, strong) IBOutlet UILabel * eventFavouriteLabel;
#end
TableCellViewController.m
#import "TableCellViewController.h"
#interface TableCellViewController ()
#end
#implementation TableCellViewController
#synthesize eventName;
#synthesize eventNameLabel;
#synthesize eventDate;
#synthesize eventDateLabel;
#synthesize eventStarttime;
#synthesize eventStarttimeLabel;
#synthesize eventEndtime;
#synthesize eventEndtimeLabel;
#synthesize eventLocation;
#synthesize eventLocationLabel;
#synthesize eventDescription;
#synthesize eventDescriptionLabel;
#synthesize eventFavourite;
#synthesize eventFavouriteLabel;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Set the eventNameLabel with the name of the event
eventNameLabel.text = eventName;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
#end
Thanks again!
This is the offending line:
destViewController.eventName = [EventsArray objectAtIndex:indexPath.row];
You're trying to assign an object of type Event stored in the array, to an object of type NSString.
Since your string is defined with the copy modifier, the assignment tries to copy to object on the right side of the assignment (Event) but apparently this object doesn't conform to the NSCopying protocol, hence the error unrecognized selector... copyWithZone....

Populating Table View with JSON Data from YouTube User's Uploads - iOS

I'm struggling to populate a Table View using JSON Data from Youtube (V 2.1) which has been parsed(Logged the output in the console)
Every time I am loading the Table View Controller, nothing is populated. I have even created a 'Video' class (NSObject). I'm struggling to understand what I'm doing wrong.
The following is my code:
Video.h
#import <Foundation/Foundation.h>
#interface Video : NSObject
#property (nonatomic, strong) NSString *title;
#property (nonatomic, strong) NSString *description;
#property (nonatomic, strong) NSString *thumbnail;
#property (nonatomic, strong) NSString *uploadedDate;
#property (nonatomic, strong) NSURL *url;
// Designated Initializer
- (id) initWithTitle:(NSString *)title;
+ (id) videoWithTitle:(NSString *)title;
- (NSURL *) thumbnailURL;
- (NSString *) formattedDate;
#end
Video.m
import "Video.h"
#implementation Video
- (id) initWithTitle:(NSString *)title {
self = [super init];
if ( self ){
self.title = title;
self.thumbnail = nil;
}
return self;
}
+ (id) videoWithTitle:(NSString *)title {
return [[self alloc] initWithTitle:title];
}
- (NSURL *) thumbnailURL {
// NSLog(#"%#",[self.thumbnail class]);
return [NSURL URLWithString:self.thumbnail];
}
- (NSString *) formattedDate {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
NSDate *tempDate = [dateFormatter dateFromString:self.uploadedDate];
[dateFormatter setDateFormat:#"EE MMM,dd"];
return [dateFormatter stringFromDate:tempDate];
}
#end
Table View Controller implementation file (the one I'm trying to populate)
#import "FilmyViewController.h"
#import "Video.h"
#interface FilmyViewController ()
#end
#implementation FilmyViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSURL *videoURL = [NSURL URLWithString:#"http://gdata.youtube.com/feeds/api/users/OrtoForum/uploads?v=2&alt=jsonc"];
NSData *jsonData = [NSData dataWithContentsOfURL:videoURL];
NSError *error = nil;
NSDictionary *dataDictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
NSLog(#"%#",dataDictionary);
self.videoArray = [NSMutableArray array];
NSArray *videosArray = [dataDictionary objectForKey:#"items"];
for (NSDictionary *vDictionary in videosArray) {
Video *video = [Video videoWithTitle:[vDictionary objectForKey:#"title"]];
video.title = [vDictionary objectForKey:#"title"];
video.description = [vDictionary objectForKey:#"author"];
video.uploadedDate = [vDictionary objectForKey:#"uploaded"];
video.url = [NSURL URLWithString:[vDictionary objectForKey:#"url"]];
[self.videoArray addObject:video];
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#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.videoArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
Video *video = [self.videoArray objectAtIndex:indexPath.row];
// Configure the cell...
cell.textLabel.text = video.title;
cell.textLabel.text = video.description;
return cell;
}
/*
#pragma mark - Navigation
// In a story board-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
#end
Here's the JSON which I'm trying to extract from.
I looked for similar topics but didn't get any appropriate solution for this.
Research Link-one and Link-two is what i have been trying to follow.
Please let me know if there is any better approach for this.
What am i missing here?
Solution
Changed
NSArray *videosArray = [dataDictionary objectForKey:#"items"];
to:
NSArray *videosArray = dataDictionary[#"data"][#"items"];
Change
NSArray *videosArray = [dataDictionary objectForKey:#"items"];
to
NSArray *videosArray = dataDictionary[#"data"][#"items"];
Your items array is in the second level: rootJSON -> data -> items

Retain Cycle on Retain Cycles

I'm seeing a gradual build up of memory that I think might be a retain cycle.
When does this happen: Click on a custom cell that expands and injects a nib with 3 buttons into the expanded area. Clicking the cell again closes the cell, shrinks the cell's tablerow height, rotates an open indicator and removes the previously injected nib.
If I open and close the cell multiple times I see the memory gradually building up.
Any ideas what might be causing this would be greatly appreciated.
Sorry I don't have enough reputation to post photos.
Build up:
Example of retained objects(mostly Animation related):
EDIT: Using ARC and on iOS 6
MasterViewController - TableView Functions
#pragma mark - UITABLEVIEW
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.topicsArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *CellIdentifier2 = #"SRCollapsibleCellClosed";
SRCollapsibleCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
if (cell == nil) {
cell = [[SRCollapsibleCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier2];
}
SRTopic *topic = [self.topicsArray objectAtIndex:indexPath.row];
[cell updateWithTopic:topic];
if([self isCellOpen:indexPath]){
CGAffineTransform transformation = CGAffineTransformMakeRotation(M_PI/2);
cell.arrow.transform = transformation;
if(![self hasChoiceBox:cell]){
[self insertChoiceBox:cell atIndex:indexPath];
}
} else{
CGAffineTransform transformation = CGAffineTransformMakeRotation(0);
cell.arrow.transform = transformation;
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if([self isCellOpen:indexPath]){
[self closeCellAtIndexPath:indexPath];
}
else{
NSIndexPath * openCell= self.openCellIndex;
NSIndexPath * newOpenCell= indexPath;
[self closeCellAtIndexPath:openCell];
[self openCellAtIndexPath:newOpenCell];
}
[tableView beginUpdates];
[tableView endUpdates];
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
-(CGFloat)tableView: (UITableView*)tableView heightForRowAtIndexPath: (NSIndexPath*) indexPath {
if([indexPath isEqual:self.openCellIndex]){
return 217.0;
} else {
return 63.0;
}
}
-(void)rotateCellArrowAtIndexPath:(NSIndexPath*)indexPath willOpen:(bool)willOpen Animated:(bool)animated{
// Change Arrow orientation
SRCollapsibleCell *cell = (SRCollapsibleCell*) [self.topicsTableView cellForRowAtIndexPath:indexPath];
CGAffineTransform transformation;
if(willOpen){
transformation = CGAffineTransformMakeRotation(M_PI/2);
} else {
transformation = CGAffineTransformMakeRotation(0);
}
if(animated){
[UIView animateWithDuration:.2 delay:0 options:nil animations:^{
cell.arrow.transform = transformation;
} completion:nil];
}
else{
cell.arrow.transform = transformation;
}
}
-(BOOL)isCellOpen:(NSIndexPath *)indexPath{
return [indexPath isEqual:self.openCellIndex];
}
-(void)closeCellAtIndexPath:(NSIndexPath*)indexPath{
//NSLog(#"Cell closing");
[self rotateCellArrowAtIndexPath:indexPath willOpen:NO Animated:YES];
[self removeSRChoiceBoxFromCellAtIndexPath:indexPath];
self.openCellIndex = nil;
}
-(void)openCellAtIndexPath:(NSIndexPath*)indexPath{
[self rotateCellArrowAtIndexPath:indexPath willOpen:YES Animated:YES];
SRCollapsibleCell *cell = (SRCollapsibleCell*)[self.topicsTableView cellForRowAtIndexPath:indexPath];
[self insertChoiceBox:cell atIndex:indexPath];
self.openCellIndex = indexPath;
}
-(void)removeSRChoiceBoxFromCellAtIndexPath:(NSIndexPath *)indexPath{
SRCollapsibleCell *cell = (SRCollapsibleCell*) [self.topicsTableView cellForRowAtIndexPath:indexPath];
for(id subview in cell.SRCollapsibleCellContent.subviews){
if([subview isKindOfClass:[SRChoiceBox class]]){
SRChoiceBox *tempBox = subview;
[tempBox removeFromSuperview];
tempBox.delegate = nil;
tempBox = nil;
}
}
}
-(void)insertChoiceBox: (SRCollapsibleCell *)cell atIndex:(NSIndexPath *) indexPath
{
//SRChoiceBox *newBox = [[SRChoiceBox alloc] initWithFrame:CGRectMake(0, 0, 310, 141)];
SRChoiceBox *newBox = [[SRChoiceBox alloc] init];
SRTopic *topic = [self.topicsArray objectAtIndex:indexPath.row];
[newBox updateWithSRTopic:topic];
newBox.delegate = self;
[cell.SRCollapsibleCellContent addSubview:newBox];
cell = nil;
topic = nil;
newBox = nil;
}
-(bool)hasChoiceBox:(SRCollapsibleCell *)cell{
for(UIView *subview in cell.SRCollapsibleCellContent.subviews){
if([subview isKindOfClass:[SRChoiceBox class]]){
return true;
}
}
return false;
}
SRChoiceBox - UIView object that gets inserted into cell
//.h
#protocol SRChoiceBoxDelegate <NSObject>
-(void)positionWasChoosen: (NSString *)choice topicId: (NSNumber *)topicId;
#end
#interface SRChoiceBox : UIView
-(id) initWithLabel: (NSDictionary *)labels andTopicID: (NSNumber *)topicId andFrame:(CGRect)frame;
#property (nonatomic, weak) IBOutlet UIView *SRChoiceBox;
#property (nonatomic, strong) NSNumber *SRTopicId;
#property (nonatomic, weak) id<SRChoiceBoxDelegate> delegate;
#property (weak, nonatomic) IBOutlet UILabel *agreeCount;
#property (weak, nonatomic) IBOutlet UILabel *disagreeCount;
#property (weak, nonatomic) IBOutlet UILabel *observeCount;
-(IBAction)buttonPress:(id)sender;
-(void)updateWithSRTopic:(SRTopic *)topic;
....
//.m
-(id)init{
self = [super init];
if (self) {
UINib *nib = [UINib nibWithNibName:#"SRChoiceBox" bundle:nil];
NSArray *q = [nib instantiateWithOwner:self options:nil];
[self addSubview:q[0]];
}
return self;
}
-(void)updateWithSRTopic:(SRTopic *)topic
{
self.SRTopicId = topic.topicId;
self.agreeCount.text = [NSString stringWithFormat: #"%#",topic.agreeDebaters];
self.disagreeCount.text = [NSString stringWithFormat: #"%#",topic.disagreeDebaters];
self.observeCount.text = [NSString stringWithFormat: #"%#",topic.observers];
}
- (IBAction)buttonPress:(id) sender {
int tag = [sender tag];
switch (tag) {
case 0:
[self.delegate positionWasChoosen:#"agree" topicId:self.SRTopicId];
break;
case 1:
[self.delegate positionWasChoosen: #"disagree" topicId:self.SRTopicId];
break;
case 2:
[self.delegate positionWasChoosen: #"observe" topicId:self.SRTopicId];
break;
default:
break;
}
}
- (void)dealloc
{
self.SRChoiceBox =nil;
self.SRTopicId=nil;
self.delegate=nil;
self.agreeCount=nil;
self.disagreeCount=nil;
self.observeCount=nil;
//NSLog(#"choicebox deallocated: %#", self);
}
SRCollapsibleCell -- Reusable cell
//.h
#interface SRCollapsibleCell : UITableViewCell
#property (strong) NSNumber *topicId;
#property (strong) NSDictionary *topicStats;
#property (weak, nonatomic) IBOutlet UILabel *title;
#property (weak, nonatomic) IBOutlet UILabel *subtitle;
#property (weak, nonatomic) IBOutlet UILabel *agreeDebaters;
#property (weak, nonatomic) IBOutlet UILabel *disagreeDebaters;
#property (weak, nonatomic) IBOutlet UILabel *observers;
#property (weak, nonatomic) IBOutlet UIImageView *arrow;
#property (weak, nonatomic) IBOutlet UIView *SRCollapsibleCellContent;
//-(void)updateWithTopic:(NSDictionary *) stats;
-(void)formatTitle:(NSString *)title;
-(void)updateWithTopic: (SRTopic *)topic;
#end
//.m
#implementation SRCollapsibleCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
}
return self;
}
-(void)formatTitle:(NSString *)title{
if(title.length<30){
self.title.text= title;
self.subtitle.text =#"";
} else {
NSArray *splitString = [self splitString:title maxCharacters:30];
self.title.text = splitString[0];
self.subtitle.text = splitString[1];
splitString = nil;
title = nil;
}
}
////http://www.musicalgeometry.com/?p=1197
- (NSArray *)splitString:(NSString*)str maxCharacters:(NSInteger)maxLength {
NSMutableArray *tempArray = [NSMutableArray arrayWithCapacity:1];
NSArray *wordArray = [str componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSInteger numberOfWords = [wordArray count];
NSInteger index = 0;
NSInteger lengthOfNextWord = 0;
while (index < numberOfWords && tempArray.count<2) {
NSMutableString *line = [NSMutableString stringWithCapacity:1];
while ((([line length] + lengthOfNextWord + 1) <= maxLength) && (index < numberOfWords)) {
lengthOfNextWord = [[wordArray objectAtIndex:index] length];
[line appendString:[wordArray objectAtIndex:index]];
index++;
if (index < numberOfWords) {
[line appendString:#" "];
}
}
[tempArray addObject:line];
NSMutableString *subtitle = [NSMutableString stringWithCapacity:1];
while(index<numberOfWords){
[subtitle appendString:[wordArray objectAtIndex:index]];
[subtitle appendString:#" "];
index++;
}
[tempArray addObject:subtitle];
break;
}
return tempArray;
}
//Breaks MVC but it makes the MasterVC cleaner
-(void)updateWithTopic: (SRTopic *)topic
{
[self formatTitle:topic.title];
self.topicId = topic.topicId;
self.agreeDebaters.text = [NSString stringWithFormat:#"%#",topic.agreeDebaters];
self.disagreeDebaters.text = [NSString stringWithFormat:#"%#", topic.disagreeDebaters];
self.observers.text = [NSString stringWithFormat:#"%#", topic.observers];
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
}
#end

Memory keep increasing when the UITableView scrolling

there is a strange problem I have not met ever
there is an array() including some custom object named MyClass parsed by JSONKit;
when I keep scrolling the tableview the memory will keeping increasing too.
but when replace
cell.textLabel.text = myclass.name;
with
cell.textLabel.text = #"cool";
or
cell.textLabel.text = [NSString stringWithFormate:#"a-%d", indexPath.row];
it's ok the memory with keep stable
but if I use
cell.textLabel.text = [NSString stringWithFormate:#"a-%#-i",myclass.name, indexPath.row];
it also keep increasing;
It will drive my crazy!!
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *identifier = #"Singers";
OMTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
MyClass *myclass = [self.data objectAtIndex:indexPath.row];
if (cell == nil){
cell = [[[OMTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier] autorelease];
}
cell.textLabel.text = myclass.name;
return cell;
}
MyClass
there is two class one Base another inherit
Base:
#interface OMBase : NSObject {
NSMutableDictionary *data;
NSString *name;
NSArray *keys;
}
#property (nonatomic, retain) NSString *name;
#property (nonatomic, copy) NSMutableDictionary *data;
#implementation OMBase
#synthesize data, name;
- (void)setData:(NSMutableDictionary *)adata{
if (data){
[data release];
data = nil;
}
data = [adata mutableCopy];
}
- (void)dealloc{
if (keys){
[keys release];
}
[data release];
[super dealloc];
}
- (id)init{
if (self = [super init]){
self.data = [[[NSMutableDictionary alloc] initWithCapacity:20] autorelease];
}
return self;
}
inherit:
#import "OMBase.h"
#interface OMLyric : OMBase
- (NSString *)songid;
- (NSString *)content;
#import "OMLyric.h"
#implementation OMLyric
- (NSString *)songid{
return [data objectForKey:#"songid"];
}
- (NSString *)content{
return [data objectForKey:#"content"];
}
Seems like your myclass.name getter returns a new allocated object. We can't say more without seeing myclass.

Resources