Read plist data into a NSArray but get null - objective-c

I got same warning here “local declaration hides instance variable” warning
but I got more problems...
Here is my code
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.someaddress.php"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
// create the connection with the request
// and start loading the data
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
NSLog(#"\n\nCONNECTION: %#", theConnection);
NSData *returnData = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:nil error:nil];
NSString *listFile = [[NSString alloc] initWithData:returnData encoding:NSASCIIStringEncoding];
NSMutableArray *plist = [[NSMutableArray alloc] init];
plist = [listFile propertyList];
NSLog( #"\n 1111 plist is \n%#", plist );
//I can get a plist format data here,But nothing in 2222
NSLog(#"Now you see me tableView Row Count");
NSLog(#"TOTAL PLIST ROW COUNT IS = %i", [plist count]);
// Return the number of rows in the section.
return [plist count];
}
and I got Warning here"Local declaration of 'plist' hides instance variable"
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"LightCell";
LightCell0 *cell =(LightCell0 *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[LightCell0 alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
// Set up the cell…
NSLog(#"Now you see me Load Data %i", indexPath.row);
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
//I try to get list data here But RETURN NULL
NSLog( #"\n 2222 plist is \n %#", plist);
switch (indexPath.row) {
case 0:
if ([plist valueForKey:#"nodeStatus"] == 0){
cell.lightImageView.image = [UIImage imageNamed:#"lightOff.png"];
NSLog(#"value for key Node Status : %#" ,[self.plists Valuefokey:#"nodeStatus"]);
//also return NULL !!
}
else if([self valueForKey:#"nodeStatus"] == 1){
cell.lightImageView.image = [UIImage imageNamed:#"lightOn.png"];
}
break;
case 1:
cell.lightLocation.text =[plist valueForKey:#"nodeName"] ;
if ([plist valueForKey:#"nodeStatus"] == 0){
cell.lightImageView.image = [UIImage imageNamed:#"lightOff.png"];
}
else if([plist valueForKey:#"nodeStatus"] == 1){
cell.lightImageView.image = [UIImage imageNamed:#"lightOn.png"];
};
break;
default:
break;
}
return cell;
}
This is the tow items I create in a plist
{
category = Light;
nodeID = 1;
nodeName = "Living Room";
nodeStatus = 0;
nodeTrigger = 0;
nodeType = "light_sw";
},
{
category = Light;
nodeID = 2;
nodeName = Kitchen;
nodeStatus = 0;
nodeTrigger = 0;
nodeType = "light_sw";
}
So that's my question ,Why can't I pass "plist" from
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
...
}
to
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
...
}
and I use NSMutableArray *plist = [[NSMutableArray alloc] init];
But still appear "Local declaration of 'plist' hides instance variable"
???
hope someone can figure out this problem
Best Regards !

and I got Warning here"Local declaration of 'plist' hides instance variable"
Well, then, you should fix that.
The warning is telling you that you've declared two variables named plist: One local to this instance method, and the other an instance variable. The local variable, having a narrower scope, hides the instance variable, so that when you refer to plist in the method, you are referring to the local variable. This means that you cannot access anything stored in the instance variable by another method, nor store anything in it for another method to retrieve.
The solution is either to kill off or to rename the local variable. If the latter is what you want, use Xcode's “Edit All in Scope” feature.
Also:
NSMutableArray *plist = [[NSMutableArray alloc] init];
plist = [listFile propertyList];
Creating the array on the first of those lines is redundant, because you immediately replace your pointer to that array with the pointer to another array, returned by propertyList. Thus, you never use and you leak the first array. You should at least cut out the creation of the first array, and you should probably cut out the entire first line (thereby cutting out both the first array and the local variable).

Here is the code I fix the warning ,the program can build without any warning
it also can display the result after reading the plist in tableview
1.Load the plist:
- (void)viewDidLoad {
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www. someaddress.php"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
NSData *returnData = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:nil error:nil];
NSString *listFile = [[NSString alloc] initWithData:returnData encoding:NSASCIIStringEncoding];
plist = [listFile propertyList];
}
2.return the number to rows
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [plist count];
}
3.read the plist data to show result in cells
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"LightCell0";
LightCell0 *cell =(LightCell0 *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[LightCell0 alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
// Set up the cell…
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
int i;
for (i=0; i<[plist count]; i++) {
//Get nodeName
if(indexPath.row == i)
{
cell.lightLocation.text = [[[plist objectAtIndex:i] valueForKey: #"nodeName"]description];
//Get Light Status to show the image
if ([[[plist objectAtIndex:i] valueForKey: #"nodeStatus"] intValue] == 0){
cell.lightImageView.image = [UIImage imageNamed:#"lightOff.png"];
}
else if([[[plist objectAtIndex:i] valueForKey: #"nodeStatus"] intValue] == 1){
cell.lightImageView.image = [UIImage imageNamed:#"lightOn.png"];
cell.lightSwitch.on=YES;
}
}
}
return cell;
}
It can get the right data ,and display the correct result in the tableview cells
BUTTTTTTT
If you scroll up the tableview,it's ok,when you on the top it will scroll down Automatically
When you "scroll down" the tableview,program crash ???
WHY ??? did I write anything wrong ???

plist = [listFile propertyList];=====>self.plist = [listFile propertyList];
THAT IS CORRECT

Related

objectatindex outside of loop?

This is a question hard to ask but I'm going to give it a shot anyways. I'm trying to retrieving the contents of an NSDictionary outside of the UITableCell loop. Right now, when I do retrieve its content via:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
everything works fine. But outside of that loop, in a void function of its own, the number retrieved is 0.
- (void)getVideoList{
NSString *ensdsds = #"z9yDgV3ONSU";
for (int i=0; i< [self.youtubePaginator.results count]; i++){
NSDictionary *photoshoots = [self.youtubePaginator.results objectAtIndex:i];
NSString * videoId = photoshoots[#"videoID"];
NSLog(#"Newly %#: ", videoId);
NSString *urlStrings = [NSString stringWithFormat:#"https://www.googleapis.com/youtube/v3/videos?part=id%%2C+snippet%%2C+contentDetails%%2C+statistics&id=%#&key=78587868", videoId];
NSLog(#"Arries %#", urlStrings);
NSURL *urlstats = [NSURL URLWithString:urlStrings];
NSURLRequest *requeststats = [NSURLRequest requestWithURL:urlstats];
AFHTTPRequestOperation *operationtwo = [[AFHTTPRequestOperation alloc] initWithRequest:requeststats];
operationtwo.responseSerializer = [AFJSONResponseSerializer serializer];
[operationtwo setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operationtwo, id responseObjected)
{
NSDictionary *itemed = [responseObjected objectForKey:#"items"];
for (NSDictionary *itemest in itemed )
{
YouTubeVideo *youTubeVideo = [[YouTubeVideo alloc] init];
NSDictionary* stats = [itemest objectForKey:#"statistics"];
youTubeVideo.likesCount = [stats objectForKey:#"likeCount"];
youTubeVideo.viewsCount = [stats objectForKey:#"viewCount"];
NSDictionary* channelInfo = [itemest objectForKey:#"snippet"];
youTubeVideo.channelInfo = [channelInfo objectForKey:#"channelId"];
youTubeVideo.videoUploader = [channelInfo objectForKey:#"channelTitle"];
NSLog(#"True To: %#", youTubeVideo.videoUploader);
[self.thunder addObject:youTubeVideo];
}} failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(#"Error loading %#", error);
}];
[operationtwo start]; }
}
The above code returns nothing. How do I incorporate NSIndexPath in the void function and still be able to call [self getVideoList]; in viewDidLoad.
Hope that makes sense? :/
You can get the imageURL in getVideoList by passing NSIndexPath as a parameter , you just need to create a global NSString object if you want to access it globally or you can return extracted imageURL as a return value.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString * imageURL = [self getVideoList:indexPath];
// Write your code to perform operation with the image URL.
}
Here is the getVideoList method
- (NSString *)getVideoList:(NSIndexPath *)indexPath{
NSDictionary *photoshoots = [self.youtubePaginator.results objectAtIndex:indexPath.Row];
NSString * imageURL = photoshoots[#"avatar_url"];
NSLog(#"Newly %#: ", imageURL);
NSLog(#"To find us: [%d]:%#",i,self.youtubePaginator.results[i]);
return imageURL;
}
You can update the code as per your requirement.

NSCache to store images for UITableView

I have a view controller with a table view. in each cell of the table view, i have an image which is fetched from the net - but many of them have the same image. so, what i'm doing currently is storing the fetched images in a NSCache object. it happens this way:
- (void)fetchAvatarForUser:(NSString *)uid completion:(void (^)(BOOL))compBlock
{
if (!imageCache) {
imageCache = [[NSCache alloc] init];
}
if (!avatarsFetched) {
avatarsFetched = [[NSMutableArray alloc] initWithCapacity:0];
}
if ([avatarsFetched indexOfObject:uid] != NSNotFound) {
// its already being fetched
} else {
[avatarsFetched addObject:uid];
NSString *key = [NSString stringWithFormat:#"user%#",uid];
NSString *path = [NSString stringWithFormat:#"users/%#/avatar",uid];
[crudClient getPath:path parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"%#",[operation.response allHeaderFields]);
UIImage *resImage = [UIImage imageWithData:[operation responseData]];
[imageCache setObject:resImage forKey:key];
compBlock(YES);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Got error: %#", error);
compBlock(NO);
}];
}
}
- (UIImage *)getAvatarForUser:(NSString *)uid
{
NSString *key = [NSString stringWithFormat:#"user%#",uid];
NSLog(#"Image cache has: %#",[imageCache objectForKey:key]);
return [imageCache objectForKey:key];
}
imageCache is an instance variable, and also avatarsFetched, crudClient is an AFHTTPClient object.
and, in the table view:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
PostCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[PostCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
Post *curPost = [displayedPosts objectAtIndex:indexPath.section];
cell.nickname.text = [curPost nickname];
UIImage *avatarImage = [self.delegateRef.hangiesCommunicator getAvatarForUser:curPost.userID];
if (avatarImage) {
cell.avatar.image = avatarImage;
NSLog(#"Its not null");
} else {
cell.avatar.image = [UIImage imageNamed:#"20x20-user-black"];
}
}
self.delegateRef.hangiesCommunicator returns the object (which is a retained property of the app delegate) with the imageCache as an instance variable, and the two methods at the top.
When i scroll, i see the #"Its not null" in the console, yet i don't see the fetched image but the default 20x20-user-black image. does anybody have an idea, why is this happening? what am i doing wrong?
thanks!
Your code is missing some things. I can't see where you ever call the fetchAvatarForUser:completion: method on your hangiesCommunicator and your tableView:cellForRowAtIndexPath: method is not returning the cell, so I don't think the code you posted will compile cleanly.

how to avoid NULL value in objective c

Please consider this code:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
NSURL *url = [NSURL URLWithString:#"http://localhost/faq.php?faqType=2"]; // Modify this to
NSString *jsonreturn = [[NSString alloc] initWithContentsOfURL:url]; // Pulls the URL
NSLog(#"jsonreturn=%#",jsonreturn); // Look at the console and you can see what the restults are
NSData *jsonData = [jsonreturn dataUsingEncoding:NSUTF32BigEndianStringEncoding];
NSError *error = nil;
// In "real" code you should surround this with try and catch
NSDictionary *dict = [[CJSONDeserializer deserializer] deserializeAsDictionary:jsonData error:&error];
if (dict)
{
rows = [[dict objectForKey:#"faq"] retain];
}
[jsonreturn release];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Configure the cell.
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
}
NSDictionary *dict1 = [rows objectAtIndex:indexPath.row];
NSLog(#"%#", dict1);
cell.textLabel.text = [dict1 objectForKey:#"faqQues"];
}
//if it is not getting NULL value then UItableView is ok
{"faq":[{"faqQues":"this is mr.mack?"},{"faqQues":"is he good man?"}]}
//but if the data is like NULL
{"faq":[{"faqQues":"this is mr.mack?"},{"faqQues":null}]} // then it is creating EXEC_BAD_ACCESS error,
so how to avoid NULL or check null value, or how can i fix this issue?
You can query the value before using it.
if ([dict objectForKey:#"faqQues"] == [NSNull null]) {
// value is null, use your own value here
} else {
// good value to use
}
You can also do this while enumerating as well.
for (id value in dict) {
if (value == [NSNull null]) {
// null
}
}
The docs of TouchJSON state, that JSON null values are represented using the NSNull singleton (usually used to represent nil in collections - where nil is not allowed). So you have to check against [NSNull null].
But TouchJSON allows to override the default null object:
CJSONDeserializer *theDeserializer = [CJSONDeserializer deserializer];
theDeserializer.nullObject = NULL;
Details https://github.com/TouchCode/TouchJSON (see the "Avoiding NSNull values in output." section)
My fellow programmer Conrad Kramer actually came up with this: https://gist.github.com/3362607
I would change it to a function and replace NULL values with #""

How to Fix EXC_BAD_ACCESS on NSArray Property?

This is yet another EXC_BAD_ACCESS question. Although I've done my homework and am certain that I am not over-releasing my NSArray.
So here is a snippet of my code:
tableData = [NSDictionary dictionaryWithJSONString:JSONstring error:&error];
//Collect Information from JSON String into Dictionary. Value returns a mutli
dimensional NSDictionary. Eg: { value => { value => "null"}, etc }
NSMutableArray *t_info = [[NSMutableArray alloc] init];
for(id theKey in tableData)
{
NSDictionary *get = [tableData objectForKey:theKey];
[t_info addObject:get];
[get release];
} // converting into an NSArray for use in a UITableView
NSLog(#"%#", t_info);
//This returns an Array with the NSDictionary's as an Object in each row. Returns fine
if (tvc == nil)
{
tvc = [[tableViewController alloc] init]; //Create Table Controller
tableView.delegate = tvc;
tableView.dataSource = tvc;
tvc.tableView = self.tableView;
tvc.tableData = t_info; //pass our data to the tvc class
[tvc.tableView reloadData];
}
...
Now in my TableViewController Class:
#implementation tableViewController
#synthesize tableData, tableView;
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [tableData count]; //Returns X Amount Fine.
}
- (UITableViewCell *)tableView:(UITableView *)the_tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *MyIdentifier = [NSString stringWithFormat:#"MyIdentifier"];
UITableViewCell *cell = [the_tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:MyIdentifier] autorelease];
}
NSLog(#"%#", tableData); //** CRASHES!!**
cell.textLabel.text = #"This is a test";
return cell;
}
If I were to comment out that NSLog, it'll work fine and return "this is a test" on each table row.
This one has really got me stumped, all the articles I have around about this problem is generally related to retain/memory issues.
Also, another important point.
If I were to pass through my original (NSDictionary) tableData from my first class code and run the same script in my tableViewController - I can NSLog the object perfectly fine.
The only time you need to release an object is if you have explicitly allocated it by way of new, alloc, or copy.
NSMutableArray *t_info = [[NSMutableArray alloc] init];
for(id theKey in tableData)
{
NSDictionary *get = [tableData objectForKey:theKey];
[t_info addObject:get];
[get release];
}
You shouldn't be releasing get here. By doing this, you're releasing the reference that the tableData dictionary is holding onto, which is bad. My guess is that this is what is causing the problem that you're encountering.
If I'm not mistaken, the reason why [tableData count] returns the expected value is because the array is still holding onto the references that have been released.

UITAbleView Giving Error

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
//NSLog(#"Array: %#",rows);
return [rows count];// AT THIS LINE
}
Program received signal: “EXC_BAD_ACCESS”
THANKS FOR THE REPLY
Actually I have attached it to the WebPage By NSUrl where I have made a PHP array and I have created a NSLOG where I am getting the Values in the array form but When It exceute the line return [rows count];. It gives error when I am writting statically return 2; then it execute. I am explaining to you what I am doing. I am initialising the NIb with
Name tableViewController=[[JsonTestViewController alloc] initWithNibName:#"JsonTestViewController" bundle:nil];
In JsonTestViewController.m
I have this code:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
//NSLog(#"Array: %#",rows);
return [rows 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:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
// Configure the cell.
NSDictionary *dict = [rows objectAtIndex: indexPath.row];
NSString *strlb1=[dict objectForKey:#"block"];
NSString *strlb2=[dict objectForKey:#"name"];
strlb1=[strlb1 stringByAppendingString:#" , "];
strlb1=[strlb1 stringByAppendingString:strlb2];
NSString *str1=#"FPS : ";
NSString *str2=[dict objectForKey:#"p_hours"];
NSString *strpinf;
if([str2 isEqualToString:#"FP"])
{
strpinf=#"Free Parking";
}
else if([str2 isEqualToString:#"12"])
{
strpinf=#"2 hours";
}
else if([str2 isEqualToString:#"14"])
{
strpinf=#"4 hours";
}
else if([str2 isEqualToString:#"MP"])
{
strpinf=#"Metered Parking";
}
str1=[str1 stringByAppendingString:strpinf];
cell.textLabel.text =strlb1;
cell.detailTextLabel.text = str1;
return cell;
}
- (void)viewDidLoad {
[super viewDidLoad];
NSURL *url = [NSURL URLWithString:#"SITE URL"];
NSString *jsonreturn = [[NSString alloc] initWithContentsOfURL:url];
NSData *jsonData = [jsonreturn dataUsingEncoding:NSUTF32BigEndianStringEncoding];
NSError *error = nil;
NSDictionary * dict = [[CJSONDeserializer deserializer] deserializeAsDictionary:jsonData error:&error];
if (dict)
{
rows = [dict objectForKey:#"users"];
}
NSLog(#"Array: %#",rows);
[jsonreturn release];
}
- (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.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
}
#end
can you give more info? This can be anything, but most likely, rows is pointing to memory where a valid array used to be. How did you create the rows array?
For example, your rows array or dictionary not longer pointing to valid memory if you created the rows array as an autoreleased object through a factory method in another method.
Here's another question that's pretty close to what you're describing:
EXC_BAD_ACCESS signal received
EDIT:
So looking at the code you provided, with these lines there are some possibilities:
NSDictionary * dict = [[CJSONDeserializer deserializer] deserializeAsDictionary:jsonData error:&error];
if (dict) { rows = [dict objectForKey:#"users"]; }
the deserializeAsDictionary method can return either an autoreleased dictionary or NULL. so one possibility is that rows = NULL. when you try [rows count], your program will crash. Check and see what's in error, might give you some clues.
This will cause an error even when you explicitly return 2 for numberOfRowsInSection: because in cellForRowAtIndexPath:, you're still trying to access rows, even if it could possibly be NULL.
the other possibility lies in how you've defined rows. I'm guessing it's a property in your class. But where you have rows=[dict objectForKey:#"users"];, rows can point to nothing after the method's finished. Rows will still have the address of where [dict objectForKey:] was, but after the scope of the method, dict may be gone and all the data that comes with it.
NSDictionary * dict = [[CJSONDeserializer deserializer] deserializeAsDictionary:jsonData error:&error];
under the KVC guidelines, you should expect dict to autorelease after the end of method.
and another possibility is, since i don't know the specifics of the JSON class you're using, is that when you release jsonreturn, you're also dealloc'ing all the data associated with it. So in effect, rows is pointing to nothing.
case in point, the error seems to be rooted in how you're setting/retaining/accessing rows.
try using the Build->Build&Analyze in xcode. it might give you some more hints. or throw in a bunch of NSLog(#"%d",[rows count]); all over. also try using the debugger. it'll give you a trace of method calls that lead up to [rows count] faulting.