buzzfeed / mattress

iOS Offline Caching for Web Content
MIT License
520 stars 45 forks source link

Add dependeny and update documenation #26

Closed ogezue closed 9 years ago

ogezue commented 9 years ago

Hi, could you please add Reachability as a dependency and/ or write this in the documentation? I added pod 'ReachabilitySwift', '~> 2.1' to my podfile and needed to update your example to the code below:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

        setupCaching()

        return true
    }

    private func setupCaching(){

        do{
            let reach = try Reachability.reachabilityForInternetConnection()
            try reach.startNotifier()
            let kB = 1024
            let MB = 1024 * kB
            let GB = 1024 * MB
            let isOfflineHandler: (() -> Bool) = {
                let isOffline = reach.currentReachabilityStatus == Reachability.NetworkStatus.NotReachable
                return isOffline
            }
            let urlCache = Mattress.URLCache(memoryCapacity: 20 * MB, diskCapacity: 20 * MB, diskPath: nil,
                mattressDiskCapacity: 1 * GB, mattressDiskPath: nil, mattressSearchPathDirectory: .DocumentDirectory,
                isOfflineHandler: isOfflineHandler)

            NSURLCache.setSharedURLCache(urlCache)
        }
        catch let err as NSError {
            print("Error with caching: " + err.localizedDescription)
        }
    }
ogezue commented 9 years ago

The snippet below also doesn't compile in iOS9 because the interface seems to have changed...

It would be very helpful if you could provide a demo project.

if let cache = NSURLCache.sharedURLCache() as? Mattress.URLCache {
    let url = NSURL(string: "http://www.buzzfeed.com")!
    cache.diskCacheURL(url) { [unowned self] webView in
        var state = webView.stringByEvaluatingJavaScriptFromString("document.readyState")
        if state == "complete" {
            // Loading is done once we've returned true
            return true
        }
        return false
    }
}
lordkev commented 9 years ago

Thanks, I will check into this and create an example project. We'd like to avoid adding Reachability as a dependency so that apps can use whatever they are already using for their other reachability needs. However I'll definitely get the README updated to make this clear.

ogezue commented 9 years ago

Thanks for the example! Unfortunately it crahes on the device:

dyld: Library not loaded: @rpath/Mattress.framework/Mattress
  Referenced from: /var/mobile/Containers/Bundle/Application/06C714F0-3FDE-45D6-A73F-3B8A1DC8ECEA/MattressExample.app/MattressExample
  Reason: image not found

I think the example could be improved implementing an textfield for urls. so users can check if it really works with their url. otherwise the caching will stop at the google page.

Another thing that would improve the example is to demonstrate how the fallback would work. In case of a working connection it should fetch the page from the internet and update the cache (every visited site). And if there is no (or very slow networking (just dreaming)) it should use the cached data.

By the way: The completion handler is not called with my example url

lordkev commented 9 years ago

It sounds like you may have not run the example from the workspace. When run this way it will build Mattress as a dependency, otherwise the framework won't be there and you'll see the issue you've run into. I've verified it's working for me (after cleaning and deleting derived data just in case), so if you still have issues from the workspace let me know. Instructions were added to the README to hopefully make this clear.

Unfortunately it's not as simple as adding a text field to load a different URL, as there often may be additional work that has to be done in the diskCacheURL loadedHandler. For example, if images are loaded lazily / progressively, the JS methods to load these images will have to be triggered. If you are caching web content under your control, it's possible to make this process easy (or even unneeded), but for arbitrary pages there may be some work that has to be done to figure out what all needs to be done to fully load content for a particular page. This should probably be more clear in the README.

Caching must be done manually for each URL, but fallback when loading a URL in any UIWebView is automatic based on what is returned to the isOfflineHandler setup in the app delegate. In most cases this will just be returning the offline status from Reachability or something of that nature, but you could possibly create a more complex set of rules. However, I think that's outside the scope of an example.

If the completion handler is not being called, it is likely that you're never returning true in the loadedHandler. If you are returning true and the completion handler is not being called, please open a separate issue.

Thanks!

ogezue commented 9 years ago

Sorry - but the error remains. I have downloaded the code again, opened the workspace and did a clean. It still runs on the simulator but crashes on the device with the described error above.

Is it not possible to cache every visited site I was on automatically? The textfield is not needed anymore as I have adjusted the example url.

ogezue commented 9 years ago

Could you please remove the "stuff is nil" comment? It fills my console :)

lordkev commented 9 years ago

I've fixed the example project so that it should build on device now.

I've also pushed out a new version 1.0.1 that includes the removal of the debug log statements. :)

Caching every site visited is not something that is built into Mattress and a bit outside the scope of what the library was designed for. However, you may be able to make something like this work with Mattress. I'd look into UIWebViewDelegate and making calls to cache data in Mattress based on that. However, it may result in some overhead while browsing.

Thanks for all the feedback and if you run into and further snags feel free to open new issues on them.

ogezue commented 9 years ago

Thank you very much!

Perhaps it helps if I explain my context: I have a hybrid conference app with some UI-WebViews that display content from my CMS. So I'm thinking about preaching all the CMS pages and deploy them with the app. When ever the user has a working internet connection the cache to get updated. And when the user is offline he shouldn't see an empty page.

Isn't this something that is in scope of Mattress? Could you give me a hint how I should build this?

lordkev commented 9 years ago

Ah, I understand now. I thought you meant that the user could browse to arbitrary pages that should all be cached. You could probably accomplish this using Mattress, but it's not really built with the idea in mind of shipping files as part of the app. You potentially could run the app in the simulator and manually cache all of the URLs that you'll need accessible. You would then need to take Mattress's cache directory and include it as part of the app bundle that you ship, and specify this directory for the disk cache when you initialize Mattress. It should work, but you'd need to test it out. It was really meant to cache particular specific URLs on the fly, not an entire domain or site to be accessed later.