I have localstorage for a webview in a program working but it's always wiped out at the beginning of the next program run. I checked the file and it does persist after a program run but at the beginning of the next one, it wipes it out.
Here's my code:
- (void)awakeFromNib {
WebPreferences *prefs = [webView preferences];
[prefs _setLocalStorageDatabasePath:#"~/Library/Application Support/MyApp"];
[prefs setDatabasesEnabled:YES];
[prefs setLocalStorageEnabled:YES];
NSString *resourcesPath = [[NSBundle mainBundle] resourcePath];
NSString *htmlPath = [resourcesPath stringByAppendingString:#"/htdocs/index.html"];
[[webView mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:htmlPath]]];
[window setDelegate:self];
}
Any help would be appreciated! Thanks
look at the doc on WebPreferences, you init it use your webview every time, the WebPreferences is pre WebView, which cause you create a new WebPreferences every time you bring up the application. If you want to keep it persistent, you should init it with initWithIdentifier:"indentifer".
WebPreferences Class Reference
I'm sure you know the risks of using private APIs.
That said, put some breakpoints in there and see at what point the cache is blown away. Try moving the database to a temp location just before that line, then putting it back immediately afterward.
Related
In a sandboxed NSDocument-based application, any compatible document can be accessed using the NSOpenPanel, no matter where the document is saved. Without NSOpenPanel, the application can only access files in the sandbox container.
As my application manages two types of subclassed NSdocument (Text as a reader/writer and Image as a reader only), I try to implement a separate "Open Recent" menu for images. I disabled the the ordinary behaviour for them as they are opened by the user, overriding the noteNewRecentDocumentURL: (NSURL *)url method of the NSDocumentController to return NO for image urls. So that only the text documents appear in the ordinary File -> Open Recent menu (and open normally when user select them). Images are listed in a custom menu.
The problem occurs with these image urls, because the application is sandboxed: the application cannot open directly any image file listed in the dedicated menu (any reading operation returns a -54 error. This behaviour can be checked using:
[[NSFileManager defaultManager] isReadableFileAtPath:[fileURL path]]
which always returns FALSE in this situation. There is only one exception to that: when I reopen, from the dedicated Open Recent menu, a file that has been previously opened with the NSOpenPanel in the same application session, then closed: in this case isReadableFileAtPath: returns TRUE and the file can be accessed. But when application quits and restarts, recent images files cannot be accessed this way.
I identified thre solutions to deal with this problem:
Moving the image file in the sandbox container as soon as it has been accessed "legally" by the user, through the NSOpenPanel. It works, of course, but prevent the user from deciding on his own the location of his files! In the same way, duplicating the file in the sandbox is not a solution.
Creating an alias to these files in the sandbox. As I couldn't find a way to do this, I couldn't test whether this is a solution or not.
Disable the application sandboxing. But this is the worse solution as there are many reasons to use sandboxing!
Is there a 4th solution, which would authorize a read-only access to any image file, wherever it is located, without disabling the sandbox?
You can't access any file no matter what.
Also I am not sure what your second solution means, that is probably the reason you couldn't follow it. You probably wanted to refer to 'security-scoped bookmarks' and not to 'aliases' and they work very well and that is the path that you should follow.
Well Ivan's suggestion was excellent. After a few readings (less than an hour), I could implement those security-scoped bookmark. For interested people, here are the main findings.
add the feature to your sandboxed application's entitlement file
set the com.apple.security.files.bookmarks.document-scope (or the com.apple.security.files.bookmarks.app-scope, or both) key to TRUE.
Modify your document opening method (which calls the NSOpenPanel) like this:
-(void) openMyDocument:(id)sender{
// ... do your stuff
[self.panel beginWithCompletionHandler:^(NSInteger result) {
if (result == NSModalResponseOK) {
NSURL* selectedURL = [[self.panel URLs] objectAtIndex:0];
NSData *bookmark = nil;
NSError *error = nil;
bookmark = [selectedURL bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
includingResourceValuesForKeys:nil
relativeToURL:nil // Make it app-scoped
error:&error];
if (error) {
NSLog(#"Error while creating bookmark for URL (%#): %#", selectedURL, error);
}
NSString *access = [NSString stringWithFormat:#"%#%#", #"Access:", [selectedURL path]];
[[NSUserDefaults standardUserDefaults] setObject:bookmark forKey:access];
[[NSUserDefaults standardUserDefaults] synchronize];
// ... then open the document your way
}
}
}
Modify the method you created to read the file without using NSOpenPanel
- (void) openDocumentForScopedURL: (NSURL *) fileURL
NSString *accessKey = [NSString stringWithFormat:#"%#%#", #"Access:", [fileURL path]];
NSData *bookmarkData = [[NSUserDefaults standardUserDefaults] objectForKey:accessKey];
NSURL *bookmarkFileURL = nil;
if (bookmarkData == nil){
// no secured-scoped bookmark found, alert the user
return;
} else {
NSError *error = nil;
BOOL bookmarkDataIsStale;
bookmarkFileURL = [NSURL
URLByResolvingBookmarkData:bookmarkData
options:NSURLBookmarkResolutionWithSecurityScope
relativeToURL:nil
bookmarkDataIsStale:&bookmarkDataIsStale
error:&error];
[bookmarkFileURL startAccessingSecurityScopedResource];
}
// ... Then open your file, using bookmarkFileURL
// ... and do your stuff
// IMPORTANT. You must notify that stopped to access
[bookmarkFileURL stopAccessingSecurityScopedResource];
}
so I have an odd approach for loading bookmarks in a UIWebView in a browser app I am making. For the didSelectRowAtIndexPath in the Bookmarks UITableView, I have this code:
NSUserDefaults *lString = [NSUserDefaults standardUserDefaults];
[lString setValue:[bookmarks objectAtIndex:indexPath.row] forKey:#"loString"];
and then I have a modal for the selected object in the UITableView to another view controller which loads a UIWebView based on this code. So the problem is that the first time I click the table view object, the UIWebview is blank, then the second time it shows the URL that I clicked the first time. PLEASE HELP!
Thanks,
Michael
- (void)viewDidLoad
{
[super viewDidLoad];
NSUserDefaults *lString = [NSUserDefaults standardUserDefaults];
loadString = [lString valueForKey:#"loString"];
NSURL *url = [[NSURL alloc] initWithString:loadString];
NSURLRequest *togo = [[NSURLRequest alloc] initWithURL:url];
[webView loadRequest: togo];
// Do any additional setup after loading the view.
}
The -loadRequest method is asynchronous, meaning that it starts the load in another thread while your main thread's execution continues.
So the first time it's called, it shows a blank screen (because the first request is still running in another thread). The second time, because the first request has now finished, it shows that (while the second request runs in another thread). And so on.
To refresh the screen with the URL contents as soon as they load, you need to implement the -webViewDidFinishLoad method of your UIWebViewDelegate. In that method, you know the URL has finished loading, so if you refresh the web view there it should show the contents.
I'm making a soundboard app and I use this code to play mp3 files:
-(IBAction)playSound
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"mysound" ofType:#"mp3"];
AVAudioPlayer* theAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
theAudio.delegate=self;
[theAudio play];
[theAudio release];
}
When I include [theAudio release]; the sound doesn't play. If I take it out it plays but I don't want to have memory leaks. How can I fix this?
It would be very helpful if you could include whatever code I need to add. I'm new to programming (besides TrueBasic I've used in school) so I'm unfamiliar with Objective-C.
wait til the audio finishes via a delegate to release the audio. I believe there are a number of posts exactly like this on the site if you search, they will have the specific delegate code.
This is only because you use local variable. so theAudio will released immediately.
You should define it as class member and assignment it here. so when this function finished, it still work too.
My program have two classes, first of them is regular app delegate NSObject. The second one is a NSWindowController subclass with NSWindow and WebView on it, which shows html page from application bundle.
Here is how i call window from AppDelegate:
-(IBAction)showWebViewForm:(id)sender
{
webViewForm = [[WebViewForm alloc] initWithWindowNibName:#"WebViewForm"];
[webViewForm showWindow:self];
}
Here is how i render the webpage in WebViewForm : NSWindowController:
-(void)awakeFromNib{
[NSApp activateIgnoringOtherApps:YES];
[webview setUIDelegate: self];
[webview setResourceLoadDelegate: self];
[webview setPolicyDelegate:self];
[webview setFrameLoadDelegate:self];
[[webview mainFrame] loadRequest:
[NSURLRequest requestWithURL:
[NSURL fileURLWithPath:
[[NSBundle mainBundle] pathForResource:#"index" ofType:#"html" inDirectory:#"data"]]]];
}
It's work fine, but only for the first time. When i close WebViewForm window and reopen it, webpage is disappearing from WebView. Why is so that, and how to fix it?
UPD Even if embed awakeFromNib code in special new method like -(void)refreshWebview and then call [webViewForm refreshWebview] right after [webViewForm showWindow:self];, still — page loads only for first time, and it's really weird ( Any ideas?
I figure it out by myself. The problem was, that webview closed when it's parent window closed. So, there is special method for case like that:
[webview setShouldCloseWithWindow:NO];
What I'm actually trying to do is put a WebKitView into a ScreenSaver (which inherits NSView). I'm totally new to MacOS X and Cocoa (but I'm very familiar with Objective-C and used some parts of GNUStep). Do I need some laying out? I want to show only one control in the whole NSView.
In your initWithFrame:isPreview: method, create a WebView in the usual way, then, send yourself an addSubview: message, passing the web view:
webView = [[WebView alloc] initWithFrame:frame];
[self addSubview:webView];
If you're wondering what rectangle you should pass as the WebView's frame, read the View Programming Guide. Also, don't forget to release the webView in dealloc (or autorelease it in initWithFrame:isPreview:).
Once you have your web view, you'll need to load a page into it. Set a suitably long animation interval (at least a couple of seconds), and load the page in animateOneFrame:
- (void) animateOneFrame {
[[webView mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://google.com/"]]];
}
You may also want to handle WebViewProgressFinishedNotification, and put off re-loading the web view until that happens (to compensate for slow or soaked connections). You'll do this with an instance variable, which you set to YES in both initWithFrame:isPreview: and your notification-handler method, and test and set to NO in animateOneFrame:
- (void) animateOneFrame {
if (hasFinished) {
[[webView mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://google.com/"]]];
hasFinished = NO;
}
}
[aScreenSaverView addSubview:aWebKitView];
But why add a UIWebView into a screen saver view when you can just make the UIWebView take up the full screen on its own? Introducing view hierarchies where they are not needed is not a good idea because it increases the processing needed to display the interface.
You can also not worry too much about your animation interval by calling
[self stopAnimation];
at the end of your animateOneFrame method.