Dropbox detect file change using delta IOS - ios

I want the user to be advised if any file changes in the dropbox folder. To do this I have to use this code:
[self.restCLient loadDelta: nil];
and the methods:
-(void)restClient:(DBRestClient *)client loadedDeltaEntries:(NSArray *)entries reset:(BOOL)shouldReset cursor:(NSString *)cursor hasMore:(BOOL)hasMore{
NSLog(#"WORKED: %#, %#, %c, %c", entries, cursor, hasMore, shouldReset);
}
-(void)restClient:(DBRestClient *)client loadDeltaFailedWithError:(NSError *)error{
NSLog(#"THE ERROR: %#", error);
}
This is the type of response I am getting:
2013-03-06 20:46:33.373 Splash-it[1659:907] WORKED: (
"<DBDeltaEntry: 0x1e2afbf0>",
"<DBDeltaEntry: 0x1e0e4030>",
"<DBDeltaEntry: 0x1e013640>",
"<DBDeltaEntry: 0x1e28e590>"
)
How can I understand form this if something has changed in my dropbox?

This question is a bit old, but I thought I'd answer anyway. :)
You're going to want to access the properties of the DBDeltaEntry object.
Step 1: Import DBDeltaEntry.h
I have no idea why this isn't included with the rest of the Dropbox stuff (I emailed Dropbox to ask why). Add this to your class:
#import "DBDeltaEntry.h"
Step 2: Loop Through the Results
Inside the loadedDeltaEntries delegate method, you can loop through your results like this:
for(DBDeltaEntry *file in entries) {
NSLog(#"Entry name: %# / Metadata: %#",file.lowercasePath, file.metadata.filename);
}
To see what else you can access on the metadata of an DBDeltaEntry object, look inside DBMetadata.h:
BOOL thumbnailExists;
long long totalBytes;
NSDate* lastModifiedDate;
NSDate *clientMtime; // file's mtime for display purposes only
NSString* path;
BOOL isDirectory;
NSArray* contents;
NSString* hash;
NSString* humanReadableSize;
NSString* root;
NSString* icon;
NSString* rev;
long long revision; // Deprecated; will be removed in version 2. Use rev whenever possible
BOOL isDeleted;
NSString *filename;
Step 3: Understanding The Results
This list of entries represents the most recent changes to your Dropbox folder (what files were modified, deleted, or added). Using the cursor is important in the loadedDeltaEntries method because it helps you keep track of which changes you're aware of. You can store the cursor and then pass it in with each delta call to tell Dropbox "this is as far as I'm aware when it comes to changes" and Dropbox will only tell you what has changed since that cursor.
I hope that helps.

Related

iOS device unable to access an iCloud account created by another iOS device

I am revisiting a problem I presented here last year. I didn't ask the question correctly and believe I didn't provide the relevant code. I deleted that question and have rephrased it better (and longishI this time. This time I hope someone can understand my question. Maybe I have been looking too long at the screen to see my errors or iOS 10.2 has implemented new iCloud permissions.
I have universal iOS (and macOS version) app that writes and reads text files to iCloud. Writing out the files to iCloud is not a problem. It is reading them back that has got me running around it circles.
(1) If an iPad writes out the file, it can read it back into the app, but it cannot read files written out by an iPhone using the same app.
(2) If an iPhone writes out the file, it can read it back into the app, but it cannot read files written out by an iPad using the same app.
(3) The Mac can read files written out by iOS devices but iOS devices cannot read the files written out by a macOS device.
Now when an attempt is made to read the file, it fails with error code 260 - That file doesn't exist. This happens for each of the aforementioned steps above. Since it's the same universal app, it has left me completely stupefied. The devices don't add anything specific to the device to the file name. This means I have misunderstood something about the caching of iCloud files on the device. I understood that the iOS (and macOS) take of this automatically.
Here is the code from my iOS project.
This is how I set up the metaDataQuery to get the file URL from iCloud (in iOS project):
//Get list of iCloud files or read a file from iCloud
func iCloud_ListOrReadFiles(_ accountName:String)
{
//Format for search predicate of document(s) in iCloud storage
var theFormat :String
//List documents or open a document
if(listMode)
{
requestedAccountName = kSuffix //List all files with suffix kSuffix (= "txt")
theFormat = "%K ENDSWITH %#" //Just like all text documents
} else {
requestedAccountName = accountName //Read the file
theFormat = "%K LIKE %#"
}
//And now set up the metaDataQuery
metadataQuery = NSMetadataQuery()
metadataQuery!.predicate = NSPredicate.init(format:theFormat, NSMetadataItemFSNameKey,requestedAccountName!)
metadataQuery!.searchScopes = [NSMetadataQueryUbiquitousDocumentsScope]
NotificationCenter.default.addObserver(self,selector:#selector(metadataQueryDidFinishGathering),
name:NSNotification.Name.NSMetadataQueryDidFinishGathering,object:metadataQuery)
metadataQuery!.start()
}
This is how I process the file URLs returned from iCloud via the metaDataQuery (in iOS project):
func metadataQueryDidFinishGathering(_ notification:Notification)
{
let query = notification.object! as! NSMetadataQuery
query.disableUpdates() //Disable the querying updates
NotificationCenter.default.removeObserver(self, name:NSNotification.Name.NSMetadataQueryDidFinishGathering, object:query) //And remove from Notifications
query.stop() //Final nail in the coffin for this query
let results = NSArray.init(array: query.results)
let theCount = query.resultCount
//Vamoose if nothing found
if (theCount < 1) {
return
}
if(listMode) //Just create a list of iCloud files found
{
listMode = false
for i in 0..<theCount
{
let account = Accounts()
account.startDate = nil
account.stopDate = nil
account.modDate = nil //Can't set it below because the compiler is chocking up there.
account.location = 2
let urlString = ((results[i] as AnyObject).value(forAttribute: NSMetadataItemURLKey) as! URL).lastPathComponent
account.accountName = String( (urlString as NSString).deletingPathExtension)
listOfAccounts?.add(account)
}
//If user wants the list sorted alphabetiucally, then do it
if(appSettings.bSortingsFlag)
{
if( (((listOfAccounts?.count)!-1)) > onDeviceIndex) { //Sort only iCloud accounts
self.bubbleSortAccountNames(onDeviceIndex, toIndex:((listOfAccounts?.count)!-1))
}
}
} else { //Came here to read one text file
ubiquityURL = ((results[0] as AnyObject).value(forAttribute: NSMetadataItemURLKey) as? URL)! //URL of file
print(String(format:"metadataQueryDidFinishGathering:ubiquityURL = %#", ubiquityURL! as CVarArg)) //Let's see it
copyFromiCloud2Device(ubiquityURL! as NSURL) //Copy the file from iCloud (in the function below)
}
This is how I read the file from iCloud, using the iCloud URL returned by metaDataQuery. Below the code are the console prints (in iOS project):
/*
Copy the text file from iCloud using standard NSFilemanager method copyItemAtURL
No UIDocument class used here
*/
func copyFromiCloud2Device(_ iCloudURL : NSURL)
{
let nameWithSuffix = iCloudURL.lastPathComponent! //Extract just the file name (and suffix to use for target)
let deviceURL = CPLib().fullURLPath(nameWithSuffix, inFolder: nil) //My function to get full path to the Documents folder on device
print("copyToDeviceDocumentsFolder:iCloudURL \(iCloudURL)")
print("copyToDeviceDocumentsFolder:deviceURL \(deviceURL)")
do {
try FileManager.default.copyItem(at: iCloudURL as URL, to:deviceURL) //Now copy the file from iCloud
//Process the contents after 0.25 seconds
Timer.scheduledTimer(timeInterval: 0.25, target:self, selector:#selector(converText2CoreData), userInfo:nil,repeats:false)
} catch let error as NSError { // End up here with error (code 260 = The file doesn't exist)
print("copyToDeviceDocumentsFolder:nameWithSuffix = \(nameWithSuffix)")
let noSuffix = String((nameWithSuffix as NSString).deletingPathExtension) //Remove the text suffix because user doesn't need to know that
let title = String(format:"Copy '%#' from iCloud",noSuffix!)
let errorDescription = String(format:"Error (%d), %#",error.code, error.localizedFailureReason!)
CPLib().showAlert(title, message:errorDescription, button:["Done"], calledBy:self, action:nil)
}
}
These are the print statements in: "metadataQueryDidFinishGathering" and "CopyFromiCloud2Device" (in iOS project):
metadataQueryDidFinishGathering:ubiquityURL = file:///private/var/mobile/Library/Mobile%20Documents/UZMZA52SXK~com~macsoftware~CheckPad/Documents/DemAccount.txt
copyToDeviceDocumentsFolder:iCloudURL file:///private/var/mobile/Library/Mobile%20Documents/UZMZA52SXK~com~macsoftware~CheckPad/Documents/DemAccount.txt
copyToDeviceDocumentsFolder:deviceURL file:///var/mobile/Containers/Data/Application/DF9EE5C0-E3EA-444A-839D-C2E8C1D1B408/Documents/DemAccount.txt
copyToDeviceDocumentsFolder:Failed to read nameWithSuffix = DemAccount.txt
+++++++++++++
This is the Objective C code used in macOS to read the same text files from iCloud (works):
/*
Copy the file from iCloud using standard NSFilemanager method copyItemAtURL and NOT setUbiquitous.
No UIDocument implements class used here
*/
-(void)copyFromiCloud:(NSString *)fileName
{
NSString *nameWithExtension = [fileName stringByAppendingPathExtension:kTEXTOne];
NSURL *deviceURL = [[CoreDataStuff accountsLocation:nil] URLByAppendingPathComponent:nameWithExtension];
NSURL *iCloudURL = [ubiquityContainerURL URLByAppendingPathComponent:nameWithExtension];
NSFileManager *fileManager = [[NSFileManager alloc] init];
NSError *error = nil;
//Copy the file from iCloud to local directory "Documents" on device
BOOL success = [fileManager copyItemAtURL:iCloudURL toURL:deviceURL error:&error];
if (!success)
[self showAnAlert:[NSString stringWithFormat:#"Copy %# from iCloud",fileName] //Private library call
message:[NSString stringWithFormat:#"Aborting...%#",[error localizedFailureReason]] altButton:nil];
else {
[NSTimer scheduledTimerWithTimeInterval:0.25 //Set up a timer to fire up after .25 seconds
target:self
selector:#selector(convertText2CoreData:) //My function to convert the data to CoreData
userInfo:nil
repeats:NO];
}
}
I also noticed that when an iOS device fails to to find the file, this appears in the Xcode console:
**** Running on an iPad or iPhone ****
2017-03-25 20:09:15.543784 CheckPad[405:66745] [MC] System group container for systemgroup.com.apple.configurationprofiles path is /private/var/containers/Shared/SystemGroup/systemgroup.com.apple.configurationprofiles
2017-03-25 20:09:15.554561 CheckPad[405:66745] [MC] Reading from public effective user settings.
After reading the Apple iOS overview, I discovered why my iCloud file access was failing. The iOS keeps an 'iCloud container' area on the device. To read from iCloud, the OS looks at this local storage area (also known as ubiquity container)for the file. If it doesn't find it, it returns with error code 260 - That file doesn't exists. If a file has been saved to iCloud before, it just reads it from local storage. If the file has been modified by another device (later date), it downloads that version from iCloud.
To solve this, I simply used
"FileManager.default.startDownloadingUbiquitousItem(at: iCloudURL)"
with the URL returned by "metadataQueryDidFinishGathering"
then delay it for 2 seconds with:
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1), execute: {
code to download the file here
}
and then download the file. This has been working so far.

extract text from webview

I am trying to extract data from website.
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
NSLog(#"finish loading");
NSLog(#"TEXT of website \n %#",[_webView stringByEvaluatingJavaScriptFromString:#"document.documentElement.innerText;"]);
NSString *webTextString = [_webView stringByEvaluatingJavaScriptFromString:#"document.documentElement.innertext;"];
NSLog(#"Website Text: %#",webTextString);
}
NSLog is actually display data but when I copy data to NSString it always stay empty;
Here is response output:
2014-02-04 17:41:07.795 MYAPP[76113:70b] TEXT of website
...... // some more text
ouncils are warning that parts of Britain's road network could become so unsafe the they will need to be shut completely.
Local authorities in some areas say finances are so squeezed they may have to consider withdrawing maintenance from their rural road network.
......// some more text
2014-02-04 17:41:07.795 MYAPP[76113:70b] Website Text:
In the line
NSString *webTextString = [_webView stringByEvaluatingJavaScriptFromString:#"document.documentElement.innertext;"];
your capitalization is wrong. Should be innerText, not innertext.

Compare Static String and String from webview

My App sends html to a Arduino with an Ethernet Shield. The Ethernet shield acts as a webserver and sends a simple message back to a UIWebview in the App. I'm using
NSString *myText = [myWebView2 stringByEvaluatingJavaScriptFromString:#"document.body.innerHTML"];
If I ask NSLog to print my "myText" It prints out
<h2>Relay1 ON</h2>
Which is what is sent to the webview. Now if I try to Compare myText with a static string that matches exactly, I get no result.
Heres the entire code block.
- (void)webViewDidFinishLoad:(UIWebView *)myWebView2;
{
NSString *myText = [myWebView2
stringByEvaluatingJavaScriptFromString:#"document.body.innerHTML"];
NSLog(#"my Text=%#",myText);
if ([myText isEqualToString:#"<h2>Relay1 ON</h2>"]) {
NSLog (#"If statement was triggered");
}
}
If I look at the value of myText in NSLog it exactly matches yet the if statement is never triggered.
What am I missing in that if statement?
Thanks!!
Not Really Solved but I used NSRange to search myText for "Relay1 ON" and that works more efficiently than dealing with hidden Characters. Thanks so Much for your help.

is it possible to access pdf outline when developing for iOS

being that PDFKit is not available on iOS, how is it possible to get the outline of a pdf document in that environment? Is commercial libraries like FastPdfKit or PSPDFKit the only solution?
It's not TOO tricky to access the pdf outline. My outline parser has about 420 LOC. I'll post some snippets, so you'll get the idea. I can't post the full code as it's a commercial library.
You basically start like this:
CGPDFDictionaryRef outlineRef;
if(CGPDFDictionaryGetDictionary(pdfDocDictionary, "Outlines", &outlineRef)) {
going down to
NSArray *outlineElements = nil;
CGPDFDictionaryRef firstEntry;
if (CGPDFDictionaryGetDictionary(outlineRef, "First", &firstEntry)) {
NSMutableArray *pageCache = [NSMutableArray arrayWithCapacity:CGPDFDocumentGetNumberOfPages(documentRef)];
outlineElements = [self parseOutlineElements:firstEntry level:0 error:&error documentRef:documentRef cache:pageCache];
}else {
PSPDFLogWarning(#"Error while parsing outline. First entry not found!");
}
you parse single items like this:
// parse title
NSString *outlineTitle = stringFromCGPDFDictionary(outlineElementRef, #"Title");
PSPDFLogVerbose(#"outline title: %#", outlineTitle);
if (!outlineTitle) {
if (error_) {
*error_ = [NSError errorWithDomain:kPSPDFOutlineParserErrorDomain code:1 userInfo:nil];
}
return nil;
}
NSString *namedDestination = nil;
CGPDFObjectRef destinationRef;
if (CGPDFDictionaryGetObject(outlineElementRef, "Dest", &destinationRef)) {
CGPDFObjectType destinationType = CGPDFObjectGetType(destinationRef);
The most annoying thing is that you have Named Destinations in most pdf documents, which need additional steps to resolve. I save those in an array and resolve them later.
It took quite a while to "get it right" as there are LOTS of differences in the PDFs that are around, and even if you implement everything in compliance to the PDF reference, some files won't work until you apply further tweaking. (PDF is a mess!)
It is now possible in iOS 11+.
https://developer.apple.com/documentation/pdfkit
You can get the PDFOutline of a PDFDocument.
The PDFOutline's outlineRoot will return outline items if there are any and NULL if none.

"Dead Store" Warning in Xcode

I am getting a dead store warning when I analyze my project but the project does not crash.
Here is what I am doing
NSString *graphUrl = nil;
if ([graphArray count] == 1)
{
objTrial = [graphArray objectAtIndex:0];
graphUrl = #"http://chart.apis.google.com/chart?cht=s:nda&chf=bg,s,FFFFFF&chs=";
graphUrl = [graphUrl stringByAppendingString:#"&chd=t:"];
graphUrl = [graphUrl stringByAppendingString:objTrial.highValue];// get the dead store error here
}
else
{
//someother operation is done and a value is loaded to aURL
}
I get a dead store warning as mentioned in the code.. How can I prevent this?
It would be great if someone could help me out in this
The warning is telling you that the store that you do in the first line gets thrown away (i.e assigning an empty string to the variable and then reassigning it afterwards without using the original value). Just change the first line to the following and the warning should go away:
NSString *aUrl;
Edit:
you should change the line where you use it also:
aURL = [aValue copy];
"dead store" means something that's not used, or rather something useless.
You get it when you have a variable defined that you never do anything with. So, the Analyzer tells you that you have wasted some storage.
Here you haven't used the aUrl object after assigning it.
It won't cause any problems other than a few bytes of wasted memory. Of course if it's a large object that could be more.
Perhaps someone could chip in with knowledge of compilers, as compiler optimization might take care of dead stores in any case.
Dead Store is a value that is assigned but never used. There is nothing to worry about it. But if you can't control yourself from worrying ;-) you can change your code to,
NSString aUrl = nil;
if ([anArray count] == 1) {
// a value is store in aValue
// then that value is appended to aURL
aURL = [aURL stringByAppendingString:aValue];
} else {
aUrl = #"";
//someother operation is done and a value is loaded to aURL
}

Resources