Resolved Help needed in solving this mess.

Discussion in 'iPhone/iPad Programming' started by troop231, Feb 6, 2012.

  1. troop231, Feb 6, 2012
    Last edited: Mar 28, 2012

    macrumors 603

    troop231

    Joined:
    Jan 20, 2010
    #1
    Hello, I need some input on possible ways I can solve a huge issue in one of my current apps.

    Basically, my app (ORR&S) on the app store ships with about ~700MB of PDFs stored in the mainbundle. I've had a few people get annoyed with having to redownload the app update only when I update a state or two's regulations. I agree with them, it is annoying, and I therefore want to put a significant update into my app that will allow me to basically never have to submit an app update again.

    Here's what I want to do: 1.) Move all mainbundle "shipped" PDFs into a Documents folder which will tie in with point #2.) Connect to a website's folder and view the PDFs I put in there as updates. 3.) Before displaying the updates, check the modified date of the PDF files on the server against the "shipped" PDFs, then display only the ones that need updated each in a table cell and alloc an Update All button; if no new PDFs are found, display a UIAlert "No updates found" 4.) If there are updates, and the user clicks the Update All button, then begin download (with a progress indicator) and overwrite the "shipped" PDFs with the newer ones.

    Sorry for the long post, I'm sure all of this is doable, I just need some help/input on where to get started.

    Thank you in advance :)
     
  2. macrumors 65816

    jnoxx

    Joined:
    Dec 29, 2010
    Location:
    Aartselaar // Antwerp // Belgium
    #2
    Create a webservice which sends out a JSON call which holds objects like this
    PDF with int, timestamp updated, and some others if u want to, like size, name, etc.
    Then it's your time to code like, make a grid view with all the PDF's, check the timestamp of the timestamp of last updated vs the one you have (download them over NSObjects which u created yourself, i guess you can do that).
    If timestamp of last updated differs, then allow them to click download or something.
    I think that should be a small way to send you.
     
  3. macrumors 68000

    Joined:
    Jan 28, 2003
    Location:
    Less lost in L.A.
    #3
    Some random thoughts...

    Looks like you may want to look at "URL Loading System Programming Guide". NSURLConnection looks interesting. I can't say I know much about this.

    Unless there is an "Update this file" option, I don't see a need for an "Update All" button. Just initiate the update in the background one at a time. You could place one of those animated circular timing icons somewhere obvious to indicate a background process is occurring.

    If there are no updates, don't disturb the user with an alert. Don't give any feedback in this case, or perhaps have a status line for such minor information. It could also post that the user has all updates.

    If the user wants to review a PDF that is known to have an update, then give them the option to immediately update that file.

    You may think timestamps are a way to indicate a newer file, but I wonder if something simpler, like an integer value might be a better choice. Simply put, if the local PDF integer doesn't match the server value, then fetch the PDF from the server.

    Oh, I'd still ship the updates with the current PDFs. That way new users wouldn't have to initiate a "Update All" for the 700MB content. As updates occur, you'd ignore the older version of the file in app bundle and use the newer one in the document folder. If you don't update your app frequently for other reasons, this shouldn't annoy current users.

    BTW, I couldn't find your app on the app store. What's the link?
     
  4. troop231, Feb 7, 2012
    Last edited: Feb 7, 2012

    thread starter macrumors 603

    troop231

    Joined:
    Jan 20, 2010
    #4
    Is this a server side method or can it all be done from the app? Basically I just want to FTP new PDFs as I get them from each state, for example the folder would be like this: http://www.sitesnamehere.com/updates/A-Z.pdf And the app should read the contents of this folder, and compare what it finds with the modified date of the shipped PDF, then display the results in a table view.

    I'm approaching the one year mark of getting into apps, but I'm not sure where to begin, are there any good guides on how to do something like this?

    Check the first link in my signature, if you want I can PM you a promo code perhaps.

    So shouldn't the first thing I should do is put all of the mainbundle PDFs into a documents folder? How would I do this? (I want to be able to overwrite the shipped PDFs, so they need to be in a documents folder)

    Here is the current code that I use to read PDFs:

    Code:
    - (void)viewDidLoad {
        [super viewDidLoad];
    	[webView addSubview: activityIndicator];
    	self.title = @"Florida Saltwater";
    	
    	NSString *urlAddress = [[NSBundle mainBundle] pathForResource:@"FloridaSalt" ofType:@"pdf"];
    	
    	NSURL *url = [NSURL fileURLWithPath:urlAddress];	NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
    	[webView loadRequest:requestObj];
    Edit: It appears that you can't have a documents directory when submitting your app, but it has to be created by the user? I don't think there's anyway I can do what I want then :(
     
  5. macrumors 65816

    jnoxx

    Joined:
    Dec 29, 2010
    Location:
    Aartselaar // Antwerp // Belgium
    #5
    hmm, it will be more then that to be honest..
    You will need a webservice who will send out an API which your App can listen to, for example, on your iPhone, in a gridview or whatever, you want to fill that up right, so you want to do a check, so at your iPhone app, you do a call "http://yourCall.com/GIEFINFOZONFOLDER?=az"
    i don't know, just messing around, it will give u back a JSON/XML. compare those JSON/XML versus the objects u already have. on the device itself, a compare method from object vs object, and I think you're set, don't know if i'm explaining it right, but i'm sure some will understand, might care to explain better :p
     
  6. thread starter macrumors 603

    troop231

    Joined:
    Jan 20, 2010
    #6
    I guess the question I need to ask is, is it better to ship the app with no out of the box functionality at all? requiring the users to download the state pdfs they want ahead of time (This would allow the app to be purchased on 3G <20MB rule too), Or just leave it as is, shipping it with ~700MB of pdfs that are readily available even if you don't have access to an internet connection. (Downside to this is that the app can only be purchased on WiFi, and updates take about a week to get into the app store.) (Advantage is not every hunting and fishing spot has cellular service or good enough service, plus data caps for users nowdays.)

    What are your opinions? Thanks again! :cool:
     
  7. xStep, Feb 12, 2012
    Last edited: Feb 12, 2012

    macrumors 68000

    Joined:
    Jan 28, 2003
    Location:
    Less lost in L.A.
    #7
    After trying your app I came to the conclusion that you should only have the Knots page installed. That is a hefty download otherwise, and the time between uploading an update and the user downloading it could leave the user with old information.

    Read Cleaning regarding backups and Apple's change in opinion. There is an update at the regarding iOS 5.0.1. This could affect your design decisions for local device storage.

    Here are some more thoughts. I don't have experience in this realm of service. ;)

    I'd have to user select the state(s) of interest and download only those state documents. As part of that process, I'd first try downloading from the official state site if the URL is reliable. This would save you possible bandwidth charges. Upon failure of that URL, I'd then check a server that I have set up for the latest document copy that I'd have to manually or automatically keep up to date.

    How to manage that could be tricky considering you are dealing with many states. On your part, create a database on your server that you keep up to date. A copy of that would be placed onto the iOS device. I'd automatically 'call home' to check if the local copy is out of date from the server copy, and if so, download the latest version. With the local information up to date, you could check other local information against that database to confirm the user has the latest document for the states they have. If not, then ask them if they want to update them all.

    The database might have a single table with the following fields in it. Currently I'm not thinking it as to be fancy.

    State
    Document Type (fishing, hunting, etc)
    Document Title
    Document Filename
    Document File Size
    Document Date
    Document Version
    Document ISBN??
    Document Identifier Code
    State URL
    App Server URL
    App Server URL Timestamp
    Record Update Timestamp

    So how would this work?

    Well, on the server side,you'd prime the database and the downloaded documents.

    When a user request comes in for the database, part of the request would be a timestamp of the last update. That timestamp would have originated from the server and stored on the device with the database copy.

    If an update is needed, you'd download the database and timestamp to the device, and compare it the current database on the device. The database on the device would only contain records for documents download to it therefore allowing you to ignore states your customer wasn't interested in. For documents found to be newer on the server compared to the local copy, you would ask the user if they want to download the newer version.

    For the download sequence, I'd first try to download from the state URL. Only if that failed, would I use the server URL. If that fails, I would't remove the local copy, but instead let the user know that the download could not be done at this time.

    If your app gets very popular and the state URLs are not reliable or otherwise workable, you'll have to be concerned about bandwidth issues. That is something you don't have to worry about by doing the app update method you are doing right now because Apple is paying that price, for now.
     
  8. troop231, Feb 12, 2012
    Last edited: Feb 12, 2012

    thread starter macrumors 603

    troop231

    Joined:
    Jan 20, 2010
    #8
    Thanks for downloading the app!

    The only reason I won't connect to the state's url is for two reasons: One being the state servers are extremely slow and Two: the states don't post process the PDFs making them larger than necessary, when I download the PDFs, I run them through quartz filters in preview and the exported file is much smaller in size while still maintaining quality.

    So it looks like I should mark the documents directory as do not backup for iCloud?
     
  9. nehalvpatel, Feb 12, 2012
    Last edited: Feb 12, 2012

    macrumors newbie

    Joined:
    Aug 15, 2010
    #9
    I suggest using php and mySQL to pump out a plist with the documents' links and info in it. I did that for my app, here's an example: http://painkilleralready.tv/podcasts/plist.php

    All you need to do to grab that information is:
    Code:
    NSMutableArray *pdfArray = [[NSMutableArray alloc] initWithContentsOfURL:[NSURL URLWithString:@"http://yourdomain.com/pdf.php"]];
    You can then use objectAtIndex to grab the current pdf, and objectForKey to grab a certain attribute, so you can load it in a tableview.

    I'm not sure if this is exactly what you wanted, but here you go.

    EDIT: I'm assuming you're talking about your Outdoor Rules app, and if that's the case, then you'll have to nest the pdfs under categories and states. Again, plist is the way to go. You don't have to bother with parsing, it does it for you.
     
  10. macrumors 68000

    Joined:
    Jan 28, 2003
    Location:
    Less lost in L.A.
    #10
    I'm not sure as I haven't looked at it closely. The concern Marco had was the the new system would remove files from iDevice when memory was low under certain conditions. Perhaps only when using the cache and tmp areas. I just thought I should mention it as a concern to watch out for.
     
  11. thread starter macrumors 603

    troop231

    Joined:
    Jan 20, 2010
    #11
    Thank you for the information.

    So hear me out, I'll need to implement these methods:

    User taps on a state cell, we then check to see if the file has already been saved locally, if not, we download the PDF from the server (we ask first with a UIAlert due to data caps) with a UIprogressView. If we do have a local file already, we load the PDF as normally in the current version that's on the app store.

    Next, we add a check for update button on each state's view toolbar, we then connect to the server, check the file with the same name as the local one, and compare the two dates of the file, if the server contains the newer file, then lets download it and overwrite the existing file (first prompt with UIAlert saying there is a update available, would you like to download?) with a UIprogressView.

    How does this sound in comparison to the version that's already on the app store?
     
  12. macrumors 68000

    Joined:
    Jan 28, 2003
    Location:
    Less lost in L.A.
    #12
    In Apple's Clock app, in the World and Alarm screens, they have an Edit and "+" button on the top in the navigation bar. You might want to copy that idea or do something similar.

    When the user chooses the "+" button, you accept that they don't need to be queried again for permission to download the request. This 'add' button would bring up a list of all the states. I mention that, because there isn't a need to display all states for files already downloaded.

    I'm not sure why you mentioned data caps. I suppose if there is a programatic way to tell a user is going to be using their cell service for download, it is worth asking. The thing is, if they have initiated a download, shouldn't they already know this? I'm not sure of the correct answer, or practice here. :confused:

    I'd do each download in a background thread sequentially. That way the user can continue to add items to the list.

    As for the update request, either an "Check for Updates" button would work, or simply do a check in a background thread when the user starts up your app. If you keep the information limited, the bandwidth would be very small. You could limit this to occur not more than once a day also. I like the second option.

    As I was here typing all of this I was thinking about your list of states. If want to keep them all listed even when the user has no document for a state, you could use the dimming technique to indicate that a state does not have data.

    Layout your possible workflows on paper and try to understand which ones are more elegant than the others.


    Some constructive criticism and suggestions...

    I doubt all users want both the fishing and hunting regulations, so let them download only what they are interest in. That will help reduce your bandwidth needs & costs, and their wait time. I noticed Alaska has several documents for Hunting but I don't know if you want to insist they choose each of those. Perhaps a preselected check list for those would do.

    Your 'App Feedback' has no good reason to go into another screen, so don't do that. In fact, I don't know why the front screen needs to be using a table view. The front screen is a short menu, so it might be nice to place semi-transparent buttons on it with a dimmed wild life background image that you have taken or get the right to. Oh, and if your purpose for 'App Feedback' is to encourage users to write a review, then change the title to 'Review App' or 'Review ORR&S' and send them to the page App Store page that has 'Write Review' on the top of it. I use this code for that. Replace AppID with your apps AppID.

    Code:
    - (IBAction) appReviewPage:(id)sender;
    {
        NSString * urlString = [NSString stringWithString: @"itms-apps://ax.itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?type=Purple+Software&id=[COLOR="Red"]AppID[/COLOR]"];
    
        [[UIApplication sharedApplication] openURL:[NSURL URLWithString: urlString]];
    }
    You can remove or abbreviate the wording on your return arrows. For instance, instead of the one that says "Outdoor Reg...", you might consider using ORR&S as the text. Instead of "Hunting Regulations", perhaps just use "Hunting Reg." This will also give you more room the main title text.

    Wow, I was on a run there. :D
     
  13. troop231, Feb 12, 2012
    Last edited: Feb 12, 2012

    thread starter macrumors 603

    troop231

    Joined:
    Jan 20, 2010
    #13
    Thanks for all of the tips and info! I really have been wanting to get rid of the main screen table view and replace it with nice icons. The app currently is so much cleaner and better than version 1.0. It initially was created using RedFoundry, which is a joke and ran horribly slow. I then bought some iOS programming books and began to try my hand at real coding. Ever since, it's been minor upgrades that were possible based on what I had as a backbone.

    I think if you saw the way this app is setup and coded, you'll see why all of these mods will be hard to implement. Basically, I have a .plist containing a title and a view number for each state and its children. Here's the shocker: I have over 160 cases in the rootviewcontroller; when the respective case happens for the row in the plist, it alloc inits (another shocker here) a respective main file for each state, which in turn contains the correct URL for the webview or pdfview to load.

    I found no other way to do it from the rootviewcontroller, so I created a class for EACH state and for some states multiple classes, and the only difference in this classes is JUST the url for each state! Honestly it seems like a pain and overkill to create a class and header for every PDF, and it was, but I could find no other way to do it at the time.

    If you want, I can send my source without all of the PDFs so you can see how I did everything, just let me know. The app still supports iOS 3.0 also. :)
     
  14. macrumors 68000

    Joined:
    Jan 28, 2003
    Location:
    Less lost in L.A.
    #14
    We need to know if you understand the difference between a class and an object. I wonder because you mention that you 'created a class for EACH state'. There should only be one class for states, perhaps named State. You instantiate an object for each state that you have.

    Each state has one or more documents. For each document there should be an object instantiated from a Document class. Those might go into an array in the state object.

    Your outer most class seems to be a parent regulation type, which currently has two types, 'Fishing' and 'Hunting'. Those contain states.

    I'm basing the above on your app layout. It could be something different and for that we'd need to see the plist layout. Just enough to understand it.

    I've come up with my own plist. It is a dictionary of documents that are dictionaries that contain key-value pairs for the different fields. This looks simpler than an alternative I came up with based on your app layout. I like this data structure because it encapsulates the information by document. From there you can easily create other dictionaries and lists as needed.

    Here is what my plist looks like. Remember that this is only a hack. Notice that DOCID00005 has an empty LocalFileURL string, indicating that there isn't a local copy.

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
    	<key>Documents</key>
    	<dict>
    		<key>DOCID00001</key>
    		<dict>
    			<key>ParentType</key>
    			<string>Hunting</string>
    			<key>SubType</key>
    			<string>Big Game</string>
    			<key>State</key>
    			<string>Alaska</string>
    			<key>LocalFileURL</key>
    			<string>file://path/filename</string>
    			<key>ORRS_Server_URL</key>
    			<string>http://orrs_server/path/filename</string>
    			<key>StateURL</key>
    			<string>http://state.gov/path/filename</string>
    			<key>LocalDocDateTimeStamp</key>
    			<date>2012-02-13T09:39:33Z</date>
    			<key>ServerDocDateTimeStamp</key>
    			<date>2012-02-13T09:39:30Z</date>
    			<key>Title</key>
    			<string>2011-2012 Alaska Hunting Regulations</string>
    		</dict>
    		<key>DOCID00002</key>
    		<dict>
    			<key>ParentType</key>
    			<string>Hunting</string>
    			<key>SubType</key>
    			<string>Small Game</string>
    			<key>State</key>
    			<string>Alaska</string>
    			<key>LocalFileURL</key>
    			<string>file://path/filename</string>
    			<key>ORRS_Server_URL</key>
    			<string>http://orrs_server/path/filename</string>
    			<key>StateURL</key>
    			<string>http://state.gov/path/filename</string>
    			<key>LocalDocDateTimeStamp</key>
    			<date>2012-02-13T09:39:33Z</date>
    			<key>ServerDocDateTimeStamp</key>
    			<date>2012-02-13T09:39:30Z</date>
    			<key>Title</key>
    			<string>Fur Animals, Small Game, Unclassified Game and Deleterious Exotic Wildlife</string>
    		</dict>
    		<key>DOCID00005</key>
    		<dict>
    			<key>ParentType</key>
    			<string>Fishing</string>
    			<key>SubType</key>
    			<string>Salt Water</string>
    			<key>State</key>
    			<string>Florida</string>
    			<key>LocalFileURL</key>
    			<string></string>
    			<key>ORRS_Server_URL</key>
    			<string>http://orrs_server/path/filename</string>
    			<key>StateURL</key>
    			<string>http://state.gov/path/filename</string>
    			<key>LocalDocDateTimeStamp</key>
    			<date>2012-02-13T09:39:33Z</date>
    			<key>ServerDocDateTimeStamp</key>
    			<date>2012-02-13T09:39:30Z</date>
    			<key>Title</key>
    			<string>Florida Saltwater Recreational 2012 Fishing Regulations</string>
    		</dict>
    	</dict>
    </dict>
    </plist>
    
    I could use this to drill down from a top of say ParentType down to State, then SubType, and then display the document. The order isn't critical. Based on your current system, only one view controller would be needed for the listings. You'd use that for each drill downed list. In fact it might be useable for the very top, but I'd have to give that some thought.

    Time for sleep.
     
  15. thread starter macrumors 603

    troop231

    Joined:
    Jan 20, 2010
    #15
    Wow, you're sample .plist looks amazing compared to what I have. (Again, willing to provide .zip archive of source without all the PDF resources)

    Here's a sample of the way my crappy .plist is structured (you will notice from here and my rootviewcontroller why I made a class for each state):

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
       <key>Rows</key>
         <array>
    	<dict>
    			<key>Title</key>
    			<string>Fishing Regulations</string>
    			<key>Children</key>
    		  <array>
    		  <dict>
    			    <key>Title</key>
    			    <string>Arkansas</string>
    			    <key>View</key>
    			    <integer>5</integer>
    		  </dict>
    		  <dict>
    			    <key>Title</key>
    			    <string>California</string>
    			    <key>Children</key>
    			    <array>
    		  <dict>
    			    <key>Title</key>
    			    <string>Freshwater</string>
    			    <key>View</key>
    			    <integer>6</integer>
    		 </dict>
    		 <dict>
    			   <key>Title</key>
    			   <string>Saltwater</string>
    			   <key>View</key>
    			   <integer>7</integer>
    		</dict>
            </array>
       </dict>
    </array>
    </dict>
    </plist>
    and here's only PART of my rootviewcontroller, but you will see how it works hopefully.

    Code:
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    
    	//Get the dictionary of the selected data source.
    	NSDictionary *dictionary = [self.tableDataSource objectAtIndex:indexPath.row];
    	
    	//Get the children of the present item.
    	NSArray *Children = [dictionary objectForKey:@"Children"];
    	
    	if([Children count] == 0) {
    		NSInteger ViewNumber = [[dictionary objectForKey:@"View"] integerValue];
    		switch (ViewNumber) {
    			case 1: {
    				RootViewController *rvc = [[RootViewController alloc] initWithNibName:@"RootViewController" bundle:[NSBundle mainBundle]];
    				//Switch the view here
    				rvc.view = tbController.view;
    				[self.navigationController pushViewController:rvc animated:YES];
    				[rvc release];
    				}
    				break;
    			case 2: {
    				AlabamaFish *ivc2 = [[AlabamaFish alloc] initWithNibName:@"PDFView" bundle:[NSBundle mainBundle]];
    				
    				[self.navigationController pushViewController:ivc2 animated:YES]; 
    				[ivc2 release];
    				}
    				break;
    				
    			case 3: {
    				AlaskaFish *ivc3 = [[AlaskaFish alloc] initWithNibName:@"Web" bundle:[NSBundle mainBundle]];
    				
    				[self.navigationController pushViewController:ivc3 animated:YES];
    				[ivc3 release];
    			}
    				break;
    Thank you again.
     
  16. macrumors 68000

    Joined:
    Jan 28, 2003
    Location:
    Less lost in L.A.
    #16
    The difference is I think you are trying to reflect your user view of the data in your plist. I've chosen another path because I know the data structure doesn't have to match the UI layout.

    I've done a basic quick & dirty app to read the plist I created and drill down it until the user displays some content. In my case, the content is just the title I've placed in the plist for each document. Here is the directory URL. The zipped file is named; DJR Recursive VC Sample Code.zip

    The first thing I wanted to demonstrate is that you don't need many UIViewControllers for drilling down these lists, where as little as one will work in this case. (I also considered putting much of the logic into a subclass of UITableView.) It didn't sound like you were doing this.

    I used one UIVIewController for displaying each list as you drill down. To keep track of where I am, I use two variables. If they are both nil, then I'm at the top. If the first is not nil, then I'm displaying states. If both are filled in, I'm displaying document titles, or a document if there was just one. It is a bit hacky, but works for the limited levels available.

    Second, I wanted to demonstrate that a different plist layout could simplify coding. There maybe reasons for other formatting, but I like this layout for this type of app. The focus is the document which contains all the relevant information.
     
  17. troop231, Feb 14, 2012
    Last edited: Feb 14, 2012

    thread starter macrumors 603

    troop231

    Joined:
    Jan 20, 2010
    #17
    Thank you again for everything, I was able to play around with it and load a URL to a webpage that was stored from a key I added in the plist "URL"

    Code:
     NSString *urlAddress = [doc objectForKey: @"URL"];
    	NSURL *url = [NSURL URLWithString:urlAddress];	
    	NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
        [webView loadRequest:requestObj];
    I have a few questions, self.window.rootViewController is showing as only being introduced in iOS 4.0, is there a way to fix that to be compatible with iOS 3? Also, How would I set the rootView's navigation title (ORRS) without it being in the further drill downs.

    One more question, If I change the order of the plist so that Fishing is before hunting on the table, it doesn't work, the rootView always shows hunting on the top for some reason, how can I fix this?

    Thank you again :)
     
  18. xStep, Feb 14, 2012
    Last edited: Feb 15, 2012

    macrumors 68000

    Joined:
    Jan 28, 2003
    Location:
    Less lost in L.A.
    #18
    Looks like I ran into this problem in the past. Try changing self.window.rootViewController to
    Code:
    [self.window addSubview:[viewController view]];
    For the titling, lookup the navigationItem in the UIViewController class. It is a UINavigationItem class with title properties. It is a one line fix within each of those if statements within the viewDidLoad method.

    For adding the 'Review App' text, at the end of the viewDidLoad do another setValue: forKey: to the parents dictionary. Then in the didSelectRowAtIndexPath delegate method, you test for the value early and if you find it, go do what you want.

    I have written up the changes in my source, but for now I'll leave it to you to figure out the details as an exercise. Hopefully I've explained it well enough to lead you on the right path.


    Sorting is a sore point of this code. I'll have to look at it when I have time because I'm sure it will affect some logic in the current code. To get you started, look at the NSArray and NSDictionary class documentation, you'll see methods for returning sorted content. Right now I'm thinking using a sorted array of the keys would be a way to go. You could use that to get the values to populate the table, and to take actions based on selection index.
     
  19. troop231, Feb 14, 2012
    Last edited: Feb 14, 2012

    thread starter macrumors 603

    troop231

    Joined:
    Jan 20, 2010
    #19
    Your effort is greatly appreciated, once again I thank you so much for everything; it gives me something to munch on and maybe focus on for a 2-3 month rollout of implementing and tidying up everything I want.

    I was able to implement about 3 of the 5 or so features I've been wanting for awhile, and submitted an update to Apple today. The only things left that I want to implement are tackling PDF updates, and tidying up the plist/loading local PDFs and server URLs via one .h and .m files and delete the hundred or so .h and .m files I have for each state.
     
  20. macrumors 68000

    Joined:
    Jan 28, 2003
    Location:
    Less lost in L.A.
    #20
    You are welcome. I'm glad this is helping out. Yea, I figured this is a lot. It doesn't answer your original question, but simplifying up front should make that process easier too.


    Were some of those 3 things related to this thread?

    Hundreds of .h & .m files! Holy cow! Well then, my sample will save you tons of hassle.

    I've added a version 2 project file to that directory. It handles most of the items I previously mentioned and the sorting which got a little weird when I realized I was using a real key in the final stage where a list of documents can be. I added a little logic to remove the disclosure indicated for the 'Review App' selection. I even added a goto in the new version. :D

    The more I think about the server side, the more I think it should be database driven. That's a whole other bag of tricks and security headaches.
     
  21. troop231, Feb 15, 2012
    Last edited: Feb 15, 2012

    thread starter macrumors 603

    troop231

    Joined:
    Jan 20, 2010
    #21
    I will look at Version 2 here soon. The things I wanted to do were pretty basic to most people probably, move network status activityindicator to the status bar, make the review app link on the table go directly to the app's review page, and I also coded in a uialert if you have no internet connection. It's a start at least lol.

    Right now I'm having two issues: the first one is when I go to load a webpage, then touch the "back" button immediately before the webpage finishes loading, the network activity indicator in the status bar continues to move, I've tried to fix this, but it's not working. Another issue is that I can cause my app to crash replicating it in a certain way, [toolbarRefresh release]; is where the problem occurs, it's really confusing me. Let me see if I can get a screenshot of what Xcode says again.

    Edit: I was able to replicate the crash easily by doing this: Tap on a state that connects to a website (Alaska), push back button immediately, retap that state again, push back again, etc. etc. (it seems like its going into overload or something lol) It didn't take but a few taps to cause it to crash and here's a screenshot:

    [​IMG]

    Am I not releasing some stuff in the right order or something not at all perhaps? (Maybe this is also why the activityindicator continues to move while pressing back, perhaps this would solve both issues.) Thanks for your help.
     
  22. macrumors 68000

    Joined:
    Jan 28, 2003
    Location:
    Less lost in L.A.
    #22
    Forward steps in coding is always a good thing. :)


    You might want to open a new thread on these ones since it isn't related to this one except in the app name. I think you haven't supplied enough detail either. For instance, when and where are you sending the stop code to the indicator? And what class is toolbarRefresh and is it subview to something you have already release?

    I had a similar 'push back immediately' problem before. I found that I had to disable the push back button until the view controller had actually finished initialization. Specifically, the networking setup. I found this comment in my viewDidLoad method.
    Code:
    // We do this because if the user hits the back button before the networking and service browser is set up, we get a crash.
    // See netServiceBrowser delegates netServiceBrowserWillSearch: and netServiceBrowser:didNotSearch: for where we turn the button back on.
    [self.navigationItem setHidesBackButton: YES animated: NO];
    
     
  23. troop231, Feb 15, 2012
    Last edited: Feb 15, 2012

    thread starter macrumors 603

    troop231

    Joined:
    Jan 20, 2010
    #23
    Here is the indicator stop (and start) code (it's in three (void) places)

    Code:
    
    - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
        NSLog(@"ERROR");
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
        toolbarStop.hidden = YES;
        toolbarRefresh.hidden = NO;
        
    }
    
    - (void)webViewDidFinishLoad:(UIWebView *)webView {
        NSLog(@"FINISH LOAD");
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
        toolbarStop.hidden = YES;
        toolbarRefresh.hidden = NO;
        [self actualizeButtons];
    }
    
    - (void)webViewDidStartLoad:(UIWebView *)webView {
        NSString *onlineCheck = [[NSData dataWithContentsOfURL: [NSURL URLWithString:@"http://www.google.com/favicon.ico"]] retain];
        if (onlineCheck == nil) {
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Can't connect to the internet, check your connection"  delegate:self cancelButtonTitle:@"OK" otherButtonTitles: nil];
            [alert show];
            [alert release];
            
            NSLog(@"UIAlert2"); 
        }
        [onlineCheck release];
        [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
        toolbarStop.hidden = NO;
        toolbarRefresh.hidden = YES;
        
        NSLog(@"START LOAD");
        
    }
    Surely there is another way to tap the back button without making the app crash?

    It probably doesn't help that I'm not using ARC yet either.

    Edit: Is it possible to have the back button act as a stop button in my Web enabled views? (not the pdf ones)

    Basically, if a webpage is loading and the user taps the back button, its the equivalent of a stop button and a back button for the previous tableView.
     
  24. macrumors 65816

    jnoxx

    Joined:
    Dec 29, 2010
    Location:
    Aartselaar // Antwerp // Belgium
    #24
    viewWillDisappear --> make it stop there :)
     
  25. macrumors 68000

    Joined:
    Jan 28, 2003
    Location:
    Less lost in L.A.
    #25
    The networking code goes off and does it's own thing during the setup. That takes time. Exiting before that finished cause my app to crash as you described. Perhaps there is a better way, but I didn't find it. I doubt ARC will help here.

    jnoxx's suggestion is the likely solution, but...

    You can connect the back button to a local method, do the things you need done there, and then send the view controller the exit message. I think the final line in that method would be this;
    Code:
    [self.navigationController popViewControllerAnimated: YES];
     

Share This Page