Clear SDWebImage Cache - iphone

I'm working on an iPhone app which has a news feed. This news feed is pulled from a JSON web service I've written (currently living on MAMP on my laptop).
Anyway, I use a MySQL DB to store references to my images, which are stored in the apache filesystem.
I store them in a very particular way, and this is how I store them:
Full Images: ng_(postid)_(seqid)
Thumbs: tng_(postid)_(seqid)
PostID is the unique ID that is assigned to every news post.
SeqID is an ID that is only unique for the photos for that news post.
I probably didn't make that very clear... example:
The images files in the first post might look like this
ng_1_1.jpg
ng_1_2.png
ng_1_3.jpg
The image files for the second post might look like this
ng_2_1.jpg
ng_2_2.png
ng_2_3.gif
This has worked great up till now, but I tried to see what would happen if I deleted a post, and recreated one in it's place?
Let's say we have a post called 'Old Post', which has 2 images, with a postid of 7.
It's images might look like this:
ng_7_1.jpg
ng_7_2.jpg
Let's say we deleted that post, and then created a new one afterwards, which has three images and is called 'New Post'.
It's images will look like this:
ng_7_1.jpg
ng_7_2.jpg
ng_7_3.jpg
Now, here comes the problem... If the device has viewed the old post, which was deleted, and then views this new post, they will see the first two images as the ones from OLD POST. Not the new ones.
Why? SDWebImage thinks because the URL is identical, and therefore decides to pull the cached image from disk. It doesn't even display the cached version, and then check if the image has been updated.
So, I've worked out there are two possible solutions to this:
Somehow get SDWebImage to check the online image, after displaying the cached version
Pass down a key in my JSON, to tell my app to wipe SDWebImage's cache (when necessary)
So, my question is, how would you go about deleting SDWebImage's cache, or making it check the server after displaying the cached version?

I think your PostID values are not unique in your system and that causes you problems. If you had unique PostID values it would be impossible to delete a post with given ID and assign that ID value to a new post...
PostID shouldn't be reusable in my opinion - can you imagine a clerk deleting a specific order in his system, creating a new one with old ID and one day getting a call from customer that provides his order ID which is now overwritten in the system?
Other thing is that you should never ever delete cached images on client's side - be user-friendly, save bandwidth and users' data plans (check this link why that matters). However you can specify cacheMaxCacheAge for SDWebImage to get rid of old, unused images. You can also remove specific images using removeImageForKey: when for example user decides to delete a specific post on his device.
Finally, the case you're describing relates more to updating a specific post, so posts can get different image set for example. In that scenario the simplest thing you can do is to use unique images IDs, so when a post is downloaded, new images will be downloaded (old ones will be deleted when cache reaches its max age - look for cacheMaxCacheAge). Alternatively, you could introduce a kind of synchronization mechanism in your DB/JSON (e.g. based on timestamps: if a post is downloaded and has a newer timestamp than the post stored in application cache, you remove old resources and download new images, text, etc... If timestamps are equal you're good with data you already downloaded).
An advanced solution would use RestKit and Core Data which would enable users to browse your posts offline and update content (images, text) when your web resource (JSON) changes.
What an epistle... I just hope my comments are useful for you :)

Related

How to upload files and attachments to the sobject record using REST API?

Salesforce has two different UIs and in accordance with it, it has the possibility to store attached files differently.
Two files were uploaded via the classic UI and they are marked as 'attachments'. Other files were uploaded through the new UI and they are marked as 'files'.
I want to upload all of these files using REST API. I cannot find the proper documentation. Can somebody help me with this?
That's not 100% true. In SF Classic UI you were able to upload Files too. It's "just" about knowing the right API name of the table and you'll find lots of examples online.
Attachment and Document objects have exactly same API names, you can view their definitions in SOAP API definition or in REST API explorer (there was something which you can still see in screenshot in here, seems to be down now, maybe they're moving it to another area in documentation...)
The Files (incl. "Chatter Files") are stored in ContentDocument and ContentVersion object. The name is unexpected because long time ago SF purchased another company's product and it was called "Salesforce Content". In beginning it was bit of mess, now it's better integrated into whole platform but still some things lurk like File folders can be called Libraries sometimes in documentation but actual API name is ContentWorkspace. The entity relationship diagram can help a bit: https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_erd_content.htm
ContentDocument is a header to which many places in SF link (imagine file wasting space on disk only once but being cross-linked from multiple records). It can have at least 1 version and if you need to update the document - you'd upload new version but all links in org wouldn't change, they'd still link to header.
So, how to use it?
REST API guide: https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/dome_sobject_insert_update_blob.htm
or maybe Chatter API guide (you tagged it with chatter so chances are you already use it): https://developer.salesforce.com/docs/atlas.en-us.chatterapi.meta/chatterapi/connect_resources_files.htm
some of my answers here might help (shameless plug). They're about upload and reading data too and one is even about data loader... but you might experiment with exporting files first, get familiar with structure before you load?
https://stackoverflow.com/a/48668673/313628
https://stackoverflow.com/a/56268939/313628
https://stackoverflow.com/a/60284736/313628

Checking for a new version of a plist on my server

I've experimented with several ways on seeing if I need to update my user's UITableView data source only if the server one is newer. Over the past few years I've done these scenarios: 1: Having a seperate .txt file with a character as the version # then simply comparing them through code and downloading the new .plist, then saving that .txt to the user's NSDocumentDirectory along with the .plist to compare again in the future, and 2: Actually checking the server's file modification date, which worked even better, as there was no .txt file to download along with the .plist (the less stuff to download the better)
But, now I want to try a different way to account for the fact that I ship a .plist file in the App Bundle. Since the .plist file creation date is always later then the server date for new users, they don't get the new .plist file, whereas older users of the app get the new file. Sure, on the first app launch I could grab the server's modification date and overwrite the app's since I copy it from the main bundle to the NSDocumentDirectory, but I don't think I want to go that route, as I've never liked checking launch counts.
Basically, it needs to continue to be lightweight in network request time and be reliable like it's been for me. I was thinking about creating a version # key in my .plist and simply comparing that with the local .plist, but I highly doubt this will be as lightweight, as I would have to download the whole .plist into an NSDictionary first before I can compare the key values.
I'm really sorry this post is long, and I appreciate your help!
Why not ship the app with out the data_source.plist file and download it on first launch, or any other time it does not exist on disk (you never know). After that, you could send a HEAD request and check the modification date (maybe even the e-tag), and download as necessary.
UPDATE:
Depending on how much control you have over the server, you could add a hash of the file to the response headers (as mentioned in the comments: MD5,SHA*) along side Last-Modified.
You could add the data_source.plist to the bundle at build time, along with last_modified.plist where you can set the hash, last modified, and any other meta data you want, as starting point.
Checking for updates could look something like:
Send HEAD request for http://server.com/data_source.plist
Pull Last-Modified (and hash if you can send it) from the response headers
Validate against corresponding values in last_modifed.plist
Download updated data_source.plist if needed
If the download was successful, update last_modifed.plist with new meta data (last modified and has, be sure pull this from actual download response headers).
This way, the user has something to start with, and the app can download the resource when needed.
The advantage of a HEAD request is it is light weight since there is no message body, but returns the same response headers as a GET request. It is a common method to check if a resource has been updated. The trick with your scenario is to get a starting point onto the device at build time.

Advice and tips on a data-driven iPhone app

I'm doing a little iOS app for the subway of my city. It has the following features
See the map (takes you to a UIImageView to see the map of the stations)
See status (tells you if there are problems with one of the lines/stations)
See prices (tells you the different tariffs, depending on the hour)
Subway-news (little feed with the title and the first paragraph of each article, with a link to see more in safari)
Our promotions to you (takes you to a view with image-coupons shown in a overflow fashion. If you click them, you go to a certain page)
I have a server that takes the news and encode them in JSON. From the iPhone, I request the JSON async, parse it and store the info in an NSArray of NSDictionaries (with keys: date, title, content, seeMoreUrl)
This could be bought as a little RSS feed. I saw some examples and they used a SQLite db to store the data. I'm not sure how necessary would this be, as I'm only planning on showing the 5 latest news and I'm not loading the whole content, just title and a iPhone-designed paragraph.
I have serious doubts with the promotions tough. I would request a file called promotions.json with the url of each promotion and the url they link to, like this
[
{
"imgSource":"http:\/\/www.domain.com\/promotions\/1.png",
"url":"http:\/\/www.domain.com\/freeRide"
},
{
"imgSource":"http:\/\/www.domain.com\/promotions\/54.png",
"url":"http:\/\/www.cheapCarRental.com\/promotions-to-subway-users"
}
]
Then, I don't know what to do. Should I download all images to the documents folder and then when the users click in view promotions, load every pic I found in that directory intro the coverflow-like View?
Should I implement a SQLite for the news and also use it to store the images as BLOBs?
Should I just keep them in memory?
You could save the images to the Library/Caches folder (Apple won't like saving to Documents folder without good reason - my app was rejected because of this. See guidelines.). Then, you have a cache file, which is essentially a plist that saves the url (the key) and the path of its corresponding image saved on the disk (the value).
What do you want your app to do? What will users want the app to do? Would they prefer to pay the price in terms of data usage and battery usage to download all the images and probably get a snappier user experience, or would they prefer occasional lags in the interface as images are downloaded on demand in return for longer battery life and decreased data usage? It's up to you to balance those factors.

Auto fetch data from website iOS/iPhone Programming

I wanted to auto fetch data(gold price) from a website and update a variable. Do i have to load the whole .html file in a string and find the price? Is there any other way? Even if I updated the variable, how do i save it, so it retains it's updated value(price)?
Do i have to load the whole .html file
in a string and find the price?
Yes
Is there any other way?
Only if the web site also provides an API that gives you access to just the data you need.
Even if I updated the variable, how do
i save it, so it retains it's updated
value(price)?
A variable will keep it's value until you change it. However if you want to preserve it even when the user quits your app, so that it starts again from the same value, you could save it in NSUserDefaults for example.
Do be aware however, that the data is almost certainly copyright, you can't just scrape data from a website and publish an app based on that data without considering the legal perspective. Price data is normally owned by the exchange and you will need a license to re-publish it.

Where to store the complete url in a cms?

I'm creating a cms and have not yet settled on the matter of where to store the complete url for a given page in the structure.
Every page have a slug (url friendly name of the page) and every page has a nullable (for top-level pages) parent and children.
Where do I store the complete url (/first-page/sub-page) for a given page? Should this go in the database along with the other properties of the page or in some cache?
Update
It's not the database design I'm asking about, rather where to store the complete url to a given page so I don't need to traverse the entire url to get the page that the user requested (/first-page/sub-page)
Update 2
I need to find which page belongs to the currently requested url. If the requested url is /first-page/sub-page I don't want to split the url and looping through the database (obviously).
I'd rather have the entire url in the table so that I can just do a single query (WHERE url = '/first-page/sub-page') but this does not seem ideal, what if I change the slug for the parent page? Then I also need to update the url-field for all descendants.
How do other people solve this issue? Are they putting it in the database? In a cache that maps /first-page-/sub-page to the id for the page? Or are they splitting the requested url and looping though the database?
Thanks
Anders
Store it in a cache, because the web servers will need to be looking up URLs constantly. Unless you expect the URLs of pages to change very rapidly, caching will greatly reduce load on the database, which is usually your bottleneck in database driven web sites.
Basically, you want a dictionary that maps URL -> whatever you need to render the page. Many web servers will automatically use the operating system's file system as the dictionary and will often have a built-in cache that can recognize when a file changes in the file system. This would probably be much more efficient than anything you can write in your CMS. It might be better, therefore, to have you CMS implement the structure directly in the file system and handle additional mapping with hard or soft links.
I just did this for MvcCms. I went with the idea of content categories/sub categories and content pages. When a content category / subcategory is created I go recursively through the parents and build the entire route and then store it in the category table. Then when the page is requested I can find the correct content page and find out when going through a nav structure if the current nav being built is the current or active route.
This approach requires some rules about what happens when a category is edited. The approach right now is that once the full path is set for a sub category it can't be change later with the normal tools.
The source is a mvccms.codeplex.com