0

I'm kind of a noob so hopefully this isn't too complex. I'm having a problem with my code that has so far stumped and confused me and some other users. I spent some time cleaning my code, and following some tutorials, but I still get past this issue. I just know it is something really simple, so here goes:

Im making an iOS app for my blog site. It goes to the site, pulls an XML document (containing the blog title, brief description, and full article url), and parses it to display in a UITableView. To manage this, there are two custom objects: "PostList", and "Post". Post is just an object that hold the individual post data (url, title, publication date, etc) and PostList has an array that holds the Post objects, as well as some getter/setter/init functions.

That all works well. The view loads and the XML is parsed and displays in the list. The problem arises when the user either taps on a link or scrolls some cells off the screen. As far as I can tell, these are both related to the same problem. In the case of the user tapping on the cell, the view controller does not pass a value to the detailed view controller (prepareForSegue), and in the case of scrolling, the cellForRowAtIndexPath does not reinitialize the cell values.

I believe that this is al due to the same problem, that once the view has been initialized, the existing values in the PostList array are somehow deleted. The debugger says the array still sees objects inside it, but they are all blank objects. I have spent forever trying to figure out why.

If you could give me some ideas why this is happening that would be AMAZING! My code is below. I posted almost all of it since Ive had issues with not posting enough before. Hope this helps. If you need more please ask!

-Thanks in advance ;)

FirstViewController.h

 #import <UIKit/UIKit.h>
 #import "PostList.h"
 #import "Post.h"

 @interface FirstViewController : UITableViewController     

 @property (nonatomic, strong) PostList *postController;
 @property (nonatomic, strong) IBOutlet UITableView *tableView;
 @property (nonatomic, strong) Post *postToSendToDetailView;
 @property (nonatomic, strong) NSString *type;

 @end

FirstViewController.m

#import "FirstViewController.h"
#import "DetailViewController.h"
#import "Post.h"
#import "PostList.h"

@interface FirstViewController ()
@end

@implementation FirstViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.type = @"blog";
    self.postController = [[PostList alloc] initWithType:self.type];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [self.postController countOfList];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    Post *postAtSighting = [self.postController objectInListAtIndex:indexPath.row];

    // Configure the cell...
    [[cell textLabel] setText:postAtSighting.name];
    [[cell detailTextLabel] setText:postAtSighting.content];
    NSLog(@"Cell Initalized");
    return cell;
}

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"pushToDetailView"]) {
        NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
        DetailViewController *destViewController = segue.destinationViewController;
        destViewController.aPost = [self.postController objectInListAtIndex:indexPath.row];
    }
}

@end

PostList.h

#import <Foundation/Foundation.h>
#import "Post.h"

@interface PostList : NSObject

-(NSMutableArray *) getPostsofType:(NSString *)type;
-(NSString *) getName: (Post *)aPost;
-(NSUInteger) countOfList;
-(Post *)objectInListAtIndex:(NSUInteger)theIndex;
-(id)initWithType:(NSString *)type;

@property (nonatomic, strong) NSMutableArray *postsArray;
@property (nonatomic) NSString *urlString;
@property (nonatomic) NSUInteger countingIndex;

@end

PostList.m

#import "PostList.h"
#import "TBXML+HTTP.h"

@implementation PostList

- (id)initWithType:(NSString *)type {
    self = [super init];
    if (self) {    
        //Creates postArray to store Post objects
        self.postsArray = [[NSMutableArray alloc] init];

        //Create other resources
        self.urlString = [[NSString alloc] init];
        self.countingIndex = 0;
        [self getPostsofType:type];
    }
    return self;
}

-(NSString *)getName:(Post *)somePost {
    //Gets the Name of the Post object and returns the value
    NSString *name = somePost.name;
    return name;
}

-(NSMutableArray *)getPostsofType:(NSString *)type {

    //Go to the Server and get the posts that are available for the post type selected.

    //Determing the post type
    if ([type isEqual: @"blog"]) {
        self.urlString = @"http://www.biteofanapple.com/blog/feeds/blogFeed.xml";
    }
    if ([type isEqual: @"bbp"]) {
        self.urlString = @"http://www.biteofanapple.com/blog/feeds/blogFeed.xml";
    }

    //Checks for an existant xmlBlogData.xml
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents directory

    NSString* blogXML = [documentsDirectory stringByAppendingPathComponent:@"xmlBlogData.xml"];
    BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:blogXML];
    NSData *data = [[NSData alloc] init];

    //Determines the best way to handle the xml file
    if (fileExists) {
        data = [NSData dataWithContentsOfFile:blogXML];
    } else {
        NSURL *url = [NSURL URLWithString:self.urlString];

        //Goes to the Server and reads the XML file of the Posts
        data = [NSData dataWithContentsOfURL:url];
        if (data != nil) {
        NSLog(@" NSData value is not nil");
    }

        //Saves the XML data to a .dat file in the document's directory
        NSError *error;
    BOOL succeed = [data writeToFile:[documentsDirectory stringByAppendingPathComponent:@"xmlBlogData.dat"] atomically:YES];
        if (!succeed){
            // Handle error here
            NSLog(@"Error: File was unable to be written to the documents directory.");
            [error setValue:@"-1" forKey: @"File unable to be written"];
        }
    }

    //Parses the XML file
    TBXML *tbxml = [TBXML newTBXMLWithXMLData:data error:nil];

    //Prints the data Variable to NSLog
    NSLog(@"%@", [NSString stringWithUTF8String:[data bytes]]);


    //Make some placeholder variables
    if (tbxml.rootXMLElement == nil) {
        NSLog(@"XML Document does not have rootElement. Error -1");
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Sorry, there was an error" message:@"Could not find root XML element. Please contact support for help with this issue." delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
        [alert show];
    }

    TBXMLElement *element = tbxml.rootXMLElement;
    TBXMLElement *nextElement = element->nextSibling;
    NSLog(@"URLs have been set, preparing for parse/input. [PostList.getPosts]");

    //Extracts the content of the XML file and saves it to values in the Post Class
    do {
        /**********
         * This loop goes through the XML file looking for <item> tags that hold information
         * about the blog posts. It finds <item> tags and scours them for <title>, <description>, 
         * <pubdate>, and <link> tags to put into the class variables for the Post Class (aPost).
         **********/

        NSString *stringElement = [TBXML elementName:element];
        NSLog(@"%@", stringElement);

        //Creates Post variable to put stuff in.
        Post *aPost = [[Post alloc] init];

        //Sorts through the header junk to find the first <item> tag.
        if (![stringElement isEqualToString:@"item"]) {
            if (!(element->firstChild)) {
                if (!(element->nextSibling)) {
                    element = nil;
                }
                element = element->nextSibling;
            }
            element = element->firstChild;
        }
        //Once the first <item> tag is found, this code executes.
        else {
            //Now we move to the first child tag and scour its contents and its siblings
            nextElement = [TBXML nextSiblingNamed:@"item" searchFromElement:element];
            element = element->firstChild;
            do {
                //Here it loops over and over until all the parts have been collected.
                stringElement = [TBXML elementName:element];
                if ([stringElement isEqualToString:@"title"]) {
                    aPost.name = [TBXML textForElement:element];
                }
                if ([stringElement isEqualToString:@"description"]) {
                    aPost.content = [TBXML textForElement:element];
                }
                if ([stringElement isEqualToString:@"link"]) {
                    aPost.postURL = [TBXML textForElement:element];
                }
                if ([stringElement isEqualToString:@"pubdate"]) {
                    aPost.publicationDate = [TBXML textForElement:element];
                }
                element = element->nextSibling;
            } while (element->nextSibling);
            NSLog(@"%@", [self getName:aPost]);
            NSLog(@"name %@ content %@", aPost.name, aPost.content);
            [self.postsArray insertObject:aPost atIndex:self.countingIndex];
            self.countingIndex++;
            element = nextElement;

        }
    } while ((element != nil));
    return self.postsArray;
}

-(Post *)objectInListAtIndex:(NSUInteger)theIndex {
    return [self.postsArray objectAtIndex:theIndex];
}

-(NSUInteger)countOfList {
    return [self.postsArray count];
}

@end

Post.h

#import <Foundation/Foundation.h>

@class Post;

@interface Post : NSObject

@property (nonatomic, weak) NSString *name;
@property (nonatomic, weak) NSString *author;
@property (nonatomic, weak) NSString *publicationDate;
@property (nonatomic, weak) NSString *content;
@property (nonatomic, weak) NSString *postURL;

@end

Post.m

#import "Post.h"

@implementation Post

- (id)init {
    self = [super init];
    if (self) {
        self.name = @"";
        self.author = @"";
        self.content = @"";
        self.publicationDate = @"";
        self.postURL = @"";
    }
    return self;
}
@end
  • 1
    Your [earlier question](http://stackoverflow.com/q/16044970/) got deleted way too fast; I don't know if you saw the comment I posted there, but some of it still applies: This is really too much code for this site (and probably for [CodeReview.SE] as well). It's hard to know exactly what to post, I realize, but a better option might be this: there are a couple of iOS chat rooms here where someone may be able to talk with you about doing a little debugging, isolating your problem, and paring down the code so that it's manageable in a single question here. – jscs Apr 17 '13 at 02:55
  • Thanks. I really appreciate it. Thanks. I didnt know about that. Yeah it was removed quickly. My bad for posting the wrong type of question! – sonicrocketman Apr 17 '13 at 02:58
  • Sure thing. Basically, the steps you need to follow right now are: identify a suspect line or function that could be causing the trouble, and change it somehow (maybe by commenting it out). Then see if the problem persists. If so, you've got the wrong piece, so look for another. Repeat until you find it. This process is something you'll need for all the programming you ever do. You'll also probably get to know the code better, and you might even solve the problem yourself. Good luck. – jscs Apr 17 '13 at 03:08
  • By the way, you should feel free to come back and edit this post down when you have a more precise question. If it gets closed, just click the "flag" link and write a quick message to the moderators in the "other" box, asking for the question to be reopened. – jscs Apr 17 '13 at 03:10
  • I'm not going to read through all this, but I think it's worth noting that in your `tableView:cellForRowAtIndexPath:` method, if `[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];` returns nil you never actually instantiate a `UITableViewCell` to return. – Aaron Golden Apr 17 '13 at 03:10
  • Thanks @Aaron. I just saw that, and I fixed it. This is exactly what I mean, Im not seeing simple things. – sonicrocketman Apr 17 '13 at 03:14
  • I haven't read all of the code, but I think the problem is you are using weak references for the properties in your Post class... Let me know if this helps you. – josh-fuggle Apr 17 '13 at 04:37
  • @fuggle YOU ARE A GOD AMONG MEN! I HAVE BEEN DEALING WITH THIS FOR ALMOST 2 WEEKS. YOU FIXED IT!!!!!!!!!!!!!!!!!!!!! OMG, I guess I should actually research what those mean... In the mean time, THANK YOU. Thank ALL of you for your undying patience with me. And thank you fuggle YOU ARE THE BEST! – sonicrocketman Apr 17 '13 at 04:43
  • Nps dude, glad I can help - I have posted an answer so I can get some points :) – josh-fuggle Apr 17 '13 at 04:46
  • I wish I could UPVOTE you but I dont have the minimum reputation points yet... – sonicrocketman Apr 17 '13 at 04:47
  • That's okay man, glad I helped regardless. All the best. – josh-fuggle Apr 17 '13 at 04:53

1 Answers1

1

As I posted in the comment above, the problem is you are using weak references in your Post class. Try this code instead:

#import <Foundation/Foundation.h>

@class Post;

@interface Post : NSObject

@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *author;
@property (nonatomic, strong) NSString *publicationDate;
@property (nonatomic, strong) NSString *content;
@property (nonatomic, strong) NSString *postURL;

@end

If you want to learn about the differences between strong and weak references, take a look at this question: Differences between strong and weak in Objective-C

Also note that the default reference type for objective-c properties is strong, so you can omit the strong keyword if you wish.

Community
  • 1
  • 1
josh-fuggle
  • 3,097
  • 2
  • 26
  • 27