FOlder Watcher - Cocoa/Obj C - objective-c

I need to watch a specified folder for specific type of file (pdf) and get notification only when file is "Created" or "Renamed".
I tried many Obj c wrappers like SCEvents, UKKQueue etc., I could not get the type of the event raised("Created" or "Renamed") inside the notification delegate.I am just getting a flag/some#.I also tried FSEventStream which was not raising callback.Refered URL for this:OSX FSEventStreamEventFlags not working correctly.
In SCEvents, I have below delegate which is not telling me the type of event-
- (void)pathWatcher:(SCEvents *)pathWatcher eventOccurred:(SCEvent *)event {
NSLog(#"%#", event);
}
Getting below log-
2014-02-27 16:41:59.342 PMLauncher6[5187:303] <SCEvent { eventId = 661674, eventPath = /Users/Test, eventFlag = 67584 } >
Any one has any idea on the same or better way to meet the requirement, kindly advise.
Thanks

Try NSWorkspace - noteFileSystemChanged:.
The documentation doesn't tell much about it, but as a Notification that "Informs the NSWorkspace object that the file system changed at the specified path." it should fit to your needs.

Related

Location authorization error even though I've asked for authorization in iOS 8 using swift

I have an app using the location services. If the app first starts, it ask the user for permission.
For some reason, if I tap on "Allow" I'll get this message:
Trying to start MapKit location updates without prompting for location authorization.
I know what this means, but I've set breakpoints all over my code and I am SURE that nothing tries to read the user location before it is allowed to do so.
Anyway, I seem to be missing something.
1) Is there a "common mistake" which one could do, something within the storyboard or so?
2) Will Apple reject an app that has such an error?
Thing is that the app works perfectly well, The only thing is that I see this message within the console. I don't know whether Apple will see this message too and if this would be a reason to reject an app..
if ([self.locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)]) { // iOS8+
// Sending a message to avoid compile time error
[[UIApplication sharedApplication] sendAction:#selector(requestWhenInUseAuthorization)
to:self.locationManager
from:self
forEvent:nil];
} else {
[self.locationManager startUpdatingLocation];
}
}
I think you may need to include something like this for the requestWhenInUseAuthorization
Assume that you are using CLLocationManager. So did you make a strong reference to your locationManager object?
It seems to be a case when you requested location in local scope (variable) inside a function. Then trying to use MapKit, but locationManager object is already deallocated.
To solve that case, you should declare...
var locationManager = CLLocationManager()
... as an instance variable, then request authorization, and then using location services.
The problem was I have asked for authorization to use location services if the app is in use and I have determined the authorization like this:
func locationManager(manager: CLLocationManager!,
didChangeAuthorizationStatus status: CLAuthorizationStatus) {
switch status {
case CLAuthorizationStatus.Restricted:
locationStatus = GpsStatus.restricted
break
case CLAuthorizationStatus.Denied:
locationStatus = GpsStatus.denied
break
case CLAuthorizationStatus.NotDetermined:
locationStatus = GpsStatus.notDeterminded
break
default:
locationStatus = GpsStatus.allowed
break
}
}
This seems to be wrong, the error is gone if I explicitly check for CLAuthorizationStatus.AuthorizedWhenInUse:
func locationManager(manager: CLLocationManager!,
didChangeAuthorizationStatus status: CLAuthorizationStatus) {
switch status {
case CLAuthorizationStatus.Restricted:
locationStatus = GpsStatus.restricted
break
case CLAuthorizationStatus.Denied:
locationStatus = GpsStatus.denied
break
case CLAuthorizationStatus.NotDetermined:
locationStatus = GpsStatus.notDeterminded
break
case CLAuthorizationStatus.AuthorizedWhenInUse:
locationStatus = GpsStatus.allowed
default:
locationStatus = GpsStatus.notDeterminded
break
}
}
EDIT:
Seems like it's also a problem to add a TrackingLocationButton before I have the permission to use location services.
So do this
var userTrackingButton = MKUserTrackingBarButtonItem(mapView: self.mapView);
self.toolBar.items?.insert(userTrackingButton, atIndex: 0)
only if you have the permission
For iOS 8 you need to define the "Privacy - Location Usage Description" in the Info.plist.
Eg. NSLocationWhenInUseUsageDescription = "Use your location to show near by stores".
or
NSLocationAlwaysUsageDescription = "Use your location to show near by stores".
This key specifies the reason for accessing the user’s location information.

CoreText CopyFontsForRequest received mig IPC error

I've been working on a BIG project (there's no point of showing any actual code anyway) and I've notice that the following message appears in the logs:
CoreText CopyFontsForRequest received mig IPC error (FFFFFFFFFFFFFECC) from font server
The error pops up as soon as a WebView has finished loading. And I kinda believe it's the culprit behind a tiny lag.
Why is that happening? What can I do to fix this?
P.S. Tried the suggested solution here to check whether it was something system-specific, but it didn't work.
More details:
The error appears when using the AMEditorAppearance.car NSAppearance file, from the Appearance Maker project. Disabling it (= not loading it all) makes the error go away.
I don't really care about the error message, other than that it creates some weird issues with fonts. E.g. NSAlert panels, with input fiels, show a noticeable flicker and the font/text seems rather messed up, in a way I'm not sure I can accurately describe. (I could post a video with that if that'd help)
This is probably related to system font conflicts and can easily be fixed:
Open Font book
Select all fonts
Go to the file menu and select "Validate fonts"
Resolve all font conflicts (by removing duplets).
Source: Andreas Wacker
Answer by #Abrax5 is excellent. I just wanted to add my experience with this problem and could not fit it into a comment:
As far as I can tell, this error is raised only on the first failed attempt to initialise an NSFont with a font name that is not available. NSFont initialisers are failable and will return nil in such a case at which time you have an opportunity to do something about it.
You can check whether a font by a given name is available using:
NSFontDescriptor(fontAttributes: [NSFontNameAttribute: "<font name>"]).matchingFontDescriptorWithMandatoryKeys([NSFontNameAttribute]) != nil
Unfortunately, this also raises the error! The following method does not, but is deprecated:
let fontDescr = NSFontDescriptor(fontAttributes: [NSFontNameAttribute: "<font name>"])
let isAvailable = NSFontManager.sharedFontManager().availableFontNamesMatchingFontDescriptor(fontDescr)?.count ?? 0 > 0
So the only way I found of checking the availability of a font of a given name without raising that error is as follows:
public extension NSFont {
private static let availableFonts = (NSFontManager.sharedFontManager().availableFonts as? [String]).map { Set($0) }
public class func available(fontName: String) -> Bool {
return NSFont.availableFonts?.contains(fontName) ?? false
}
}
For example:
NSFont.available("Georgia") //--> true
NSFont.available("WTF?") //--> false
(I'm probably overly cautious with that optional constant there and if you are so inclined you can convert the returned [AnyObject] using as! [String]...)
Note that for the sake of efficiency this will not update until the app is started again, i.e. any fonts installed during the app's run will not be matched. If this is an important issue for your particular app, just turn the constant into a computed property:
public extension NSFont {
private static var allAvailable: Set<String>? {
return (NSFontManager.sharedFontManager().availableFonts as? [String]).map { Set($0) }
}
private static let allAvailableAtStart = allAvailable
public class func available(fontName: String) -> Bool {
return NSFont.allAvailable?.contains(fontName) ?? false
}
public class func availableAtStart(fontName: String) -> Bool {
return NSFont.allAvailableAtStart?.contains(fontName) ?? false
}
}
On my machine available(:) takes 0.006s. Of course, availableAtStart(:) takes virtually no time on all but the first call...
This is caused by calling NSFont fontWithFamily: with a family name argument which is not available on the system from within Chromium's renderer process. When Chromium's sandbox is active this call triggers the CoreText error that you're observing.
It happens during matching CSS font family names against locally installed system fonts.
Probably you were working on a Chromium-derived project. More info can be found in Chromium Bug 452849.

How can I suppress the autosave “The file has been changed by another application” alert?

I have a NSDocument subclass that presents a text document from disk. I’m trying to make it refresh automatically on detecting file changes on disk. I’ve overridden -presentedItemDidChange like this:
- (void)presentedItemDidChange
{
[super presentedItemDidChange];
// Ignoring bundles and error-handling for the moment.
NSData *newData = [NSData dataWithContentsOfURL:self.presentedItemURL];
self.textView.string = [[NSString alloc] initWithData:newData encoding:NSUTF8StringEncoding];
}
The UI refreshes fine when the file is changed in another application. The problem is, I get this dialog when I try to save the document in my application after it is modified by another app:
I kind of have an idea why this happens (not sure whether it’s correct): The modification time of the document is later (because it’s modified by another application) than the latest saved version in my app. But can I notify the autosaving system that I have done something with it and let it go away? Or am I doing things wrong when I refresh the document, and I should do it some other way to handle document versions correctly? I need to consider both external applications support or do not support autosave.
Thanks in advance.
#uranusjr's answer pointed me in the right direction -- only revertDocumentToSaved: wasn't exactly the right place.
override func presentedItemDidChange() {
dispatch_async(dispatch_get_main_queue()) {
self.reloadFromFile()
}
}
func reloadFromFile() {
guard let fileURL = self.fileURL else { return }
do {
try revertToContentsOfURL(fileURL, ofType: "YOUR TYPE HERE IF NECESSARY")
} catch {
// TODO handle error
print(error)
}
}
This simply reloads the file. readFromURL(url:, ofType:) (or the NSData/file wrapper based variants) is called and you can re-create your data structures from there.
Stumbled across the solution today (finally). You can “cheat” OS X into not warning about this by reverting the document (but not the file itself) before actually updating the internal data structure:
// Somehow read the updated data.
NSString *content = ...;
// Revert the document.
// This will discard any user input after the last document save,
// so you might want to present some UI here, like an NSAlert.
[self revertDocumentToSaved:self];
// Update the internal state.
self.content = content;
Now OS X will be happy when you save the document.

ReactiveCocoa binding "networkActivityIndicator" Crushes

I have this code:
RAC(self.viewModel , password) = self.signupCell.passwordTextField.rac_textSignal;
RAC(self.viewModel , userName) = self.signupCell.usernameTextField.rac_textSignal;
RAC([UIApplication sharedApplication], networkActivityIndicatorVisible) = self.viewModel.executeRegister.executing;
At my LogIn page.
At first is runs perfect, But it user Logout and gets to the register page once again, the app crushes at the line:
RAC([UIApplication sharedApplication], networkActivityIndicatorVisible) = self.viewModel.executeRegister.executing;
With Error:
'Signal name: is already bound to key path "networkActivityIndicatorVisible" on object , adding signal name: is undefined behavior'
I'm guessing it has something to do with subscribing to UIApplication events. But I'm not sure what else can i do beside sending subscriber completed as so:
[subscriber sendCompleted]
Any one had the same problem?
thanks.
EDIT
With the help of #erikprice and #powerj1984 I found a solution:
RAC([UIApplication sharedApplication], networkActivityIndicatorVisible) = [self.viewModel.executeRegister.executing takeUntilBlock:^BOOL(id x) {
return _viewShowing;
}];
The "_viewShowing" veritable is setted to YES on ViewWillAppear, And to NO on ViewWillDisapear.
This is not the best coding.. So if anyone has a better option i would be happy to use it.
Thanks.
That error message means that you're trying to call RAC(UIApplication.sharedApplication, networkActivityIndicatorVisible) more than once. Make sure you only make that call on that specific property of that specific object one time, ever. (Or at least until such time as you dispose of the subscription, as #powerj1984 suggests.)

How can I get a console readout at runtime in an application?

For debugging purposes, I'd like to access console printouts at runtime in a way similar to the Console app current on the App Store (that can be found here).
I did some searching of the docs and I can't find anything that's provided by Apple, but I feel like I'm missing something important. Any insight?
Thanks.
You can do so using <asl.h>. Here is an example that I threw together to create an array of console messages.
-(NSArray*)console
{
NSMutableArray *consoleLog = [NSMutableArray array];
aslclient client = asl_open(NULL, NULL, ASL_OPT_STDERR);
aslmsg query = asl_new(ASL_TYPE_QUERY);
asl_set_query(query, ASL_KEY_MSG, NULL, ASL_QUERY_OP_NOT_EQUAL);
aslresponse response = asl_search(client, query);
asl_free(query);
aslmsg message;
while((message = asl_next(response)) != NULL)
{
const char *msg = asl_get(message, ASL_KEY_MSG);
[consoleLog addObject:[NSString stringWithCString:msg encoding:NSUTF8StringEncoding]];
}
if (message != NULL) {
asl_free(message);
}
asl_free(response);
asl_close(client);
return consoleLog;
}
If your device is attached to Xcode, you can see console output (NSLogs and such) in the debug area:
If you're running the app and connecting to Xcode later, I believe you can get console logs in the Organizer.
Edit: to access the log file at runtime, you should try /var/log/system.log — but even better I recommend using a custom debug function, which would write to the system log and/or a text view in your app. (Check out NSLogv, which will be useful when writing a wrapper function.) This also has the advantage of letting you disable all debug logs from one place (just change your debug function).