How to fix the app name in MKMapView's NSErrors? - mapkit

One of MKMapViewDelegate's methods is:
- (void)mapView:(MKMapView *)mapView didFailToLocateUserWithError:(NSError *)error;
If the error is that the user didn't grant location services permission to the app then the error is MKLocationErrorDomain Code=0 "Location Services Off" UserInfo={NSLocalizedDescription=Location Services Off, NSLocalizedRecoverySuggestion=Turn on Location Services in Settings > Privacy to allow (null) to determine your current location}
I think that the (null) is supposed to be the name of my app. What should I do to achieve that?
I could fix it like this but it seems like a hack:
NSString *fixedLocalizedRecoverySuggestion = [error.localizedRecoverySuggestion stringByReplacingOccurrencesOfString: #"(null)" withString:#"AppName"];

Related

MacOS - determine the Network Account Server with code

I want to detect at runtime of my Mac application (written in Objective-C) if the user's Mac is joined to an Active Directory Server or Open Directory Server and/or any sort of "network account server". And to read the string of that setting if it exists. That is, the the setting from the Login Options pane of the "Users & Groups" applet in Systems Preference. See picture below.
Specifically, just reading the string of the specified server would be sufficient.
What's API set should I be looking at to read this setting?
A computer can be bound to multiple network account servers at one time. To list them you could use the OpenDirectory framework by creating an ODSession and list all registered nodes.
#import <OpenDirectory/OpenDirectory.h>
...
ODSession *mySession = [ODSession defaultSession];
NSError *err;
NSArray *nodeNames = [mySession nodeNamesAndReturnError:&err];
NSLog(#"nodeNames=%#", nodeNames);
I'm bound to Mac-mini.local OpenDirectory Server, and that outputs this:
nodeNames=(
"/Contacts",
"/LDAPv3/Mac-mini.local",
"/Local/Default",
"/Search"
)
To get further information about a registered node, just create an ODNode instance from the node name in the nodeNames array and use that to query that node.
ODNode *node = [[ODNode alloc] initWithSession:mySession name:#"/LDAPv3/Mac-mini.local" error:&err];
Or, you could also create an ODNode instance of a top node, like the /LDAPv3 node, directly and just ask for it's subnodes, like this:
ODNode *node = [[ODNode alloc] initWithSession:mySession name:#"/LDAPv3" error:&error];
NSArray *subnodes = [node subnodeNamesAndReturnError:&err];
NSLog(#"subnodes=%#", subnodes);
That gave me this output:
subnodes=(
"/LDAPv3/Mac-mini.local"
)
Note: there is also -unreachableSubnodeNamesAndReturnError:
If you need more info about this framework, the documentation can be found here

getting info about mac OS X application programmatically

I'm looking for cocoa framework that acquires the following information for each application : vendor name, version and full application name.
Alternatively, I could use a file that contain this information ... I've tried to search it in /Application/(name).app/... but I couldn't find it in specific location that is the same for all applications.
It should be in the info.plist under CFBundleName
If you go into <application>/contents/info.plist you'll find it there
from the  documentation:
CFBundleName (String - iOS, OS X) identifies the short name of the
bundle. This name should be less than 16 characters long and be
suitable for displaying in the menu bar and the app’s Info window. You
can include this key in the InfoPlist.strings file of an appropriate
.lproj subdirectory to provide localized values for it. If you
localize this key, you should also include the key
CFBundleDisplayName.
here's an example code for acquiring version from Info.plist of a selected application:
string GetAppVersion(string app)
{
NSString *vlcFilePath = [NSString stringWithCString:app.c_str()];
NSDictionary* infoDict = [[NSBundle bundleWithPath:vlcFilePath] infoDictionary];
NSString* version = [infoDict objectForKey:#"CFBundleVersion"];
}
...
...
GetAppVersion("/Applications/Notes.app").c_str());

Why does my core data object not show up using fetch requests between related objects that were created in the same session?

This is a really weird situation which I have been battling to resolve over the last couple of days.
I have a Card entity with a To-Many relationship on a Transaction entity. I am also using Magical Record to remove the boilerplate code around managing my data store.
My problem occurs in the following order:
Create a Card object
Then create a Transaction object in another view
When I inspect the transaction count with [card.transactions count] I get 1 as the size
However, if I perform a fetch request using the same context the transaction is not there. My predicate looks like this:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"card == %# && deleted == 0", card];
So logic says that I am perhaps not saving the context after saving the transaction, but the weird thing is that if I quit the app and then rerun it, the transaction is there. Steps 1-4 work perfectly too if I create the card, quit the app and then run the app and add a transaction. Then my save transaction code works fine.
So my question is, why aren't my objects showing up using fetch requests on a newly created parent object, where "newly created" means that it was created in the same session as the child object.
My code for creating the card looks like this:
GYCard *card = [GYCard MR_createInContext:[NSManagedObjectContext MR_defaultContext]];
[[NSManagedObjectContext MR_defaultContext] MR_save];
Then when I save the transaction my code looks like this:
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_defaultContext];
NSNumber *transactionAmount = [self.numberFormatter numberFromString:self.transactionAmountLabel.text];
GYTransaction *transaction = [GYTransaction MR_createInContext:localContext];
transaction.amount = transactionAmount;
transaction.deleted = [NSNumber numberWithBool:NO];
transaction.card = self.card;
[localContext MR_save];
The code that is not working is this:
+ (int) countTransactions:(GYCard *) card {
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"card == %# && deleted == 0", card];
return [GYTransaction MR_countOfEntitiesWithPredicate:predicate inContext:[NSManagedObjectContext MR_defaultContext]];
}
The countTransactions always returns 0 if the card was created in the same session. But it works 100% if I quit the app and relaunch. It also works for adding any new transactions to the card after quitting and relaunching the app.
This appears to be a Magical Record issue. I was using the 2.0 beta branch of Magical Record and after reverting to the tagged version:1.8.3 the issue disappears. So 2.0 seems to be the culprit. It would still be interesting to know however, why version 2.0 is causing this problem.
I would strongly advise anybody who is using Magical Record to avoid the 2.0 branch until it comes out of beta.
Update: After further investigation what the 2.0 beta of Magical Record was doing was generating 2 save notifications for 1 save, this led to my app inadvertently have 2 versions of the card. This resulted in causing the transaction that I was logging to be logged on the first card but the second card obviously did not have a transaction on it. My fetch request was then fetching the second card and returning zero transactions. Quitting and restarting the app then made my app load the correct transaction from the data store and thus worked as expected.
This could be related to the includesPendingChanges property on NSFetchRequest. However the default for this is YES which means any unsaved changes should be included in any queries.
I'm not sure what the MR_ methods are doing under the hood, but the setIncludesPendingChanges: documentation states:
Special Considerations
A value of YES is not supported in conjunction with the result type
NSDictionaryResultType, including calculation of aggregate results
(such as max and min). For dictionaries, the array returned from the
fetch reflects the current state in the persistent store, and does not
take into account any pending changes, insertions, or deletions in the
context.
So I would make sure the MR_countOfEntitiesWithPredicate method is not doing anything funky. Maybe try calling the standard - (NSUInteger)countForFetchRequest:(NSFetchRequest *)request error: (NSError **)error method on your context and see what that returns.

Simplest way to get the PID of a recently launched application

I want to launch a file with a specified application, and I want the launched program to immediately become the frontmost window.
I know that I can do this as follows:
[[NSWorkspace sharedWorkspace] openFile:fileName withApplication:appName];
Then, if I can get the PID of that launched application, I can then do this to make that application frontmost:
NSRunningApplication* app = [NSRunningApplication
runningApplicationWithProcessIdentifier: PID];
[app activateWithOptions: NSApplicationActivateAllWindows];
The question I have is this: what is the simplest, quickest, and most reliable way to get this application's PID right after launching, so I can make sure that this application is frontmost?
This is not as straightforward as it might appear at first glance. For example, I need a process name in order to get the PID using Carbon calls, or via the application dictionary that is accessible via NSRunningApplication. However, in the general case, I don't always know what the process name is, and in some cases, the process name is an empty string.
Furthermore, I might have other instances of this same application already running, and I want to always get the PID of the specific instance of the application that I just launched.
Can anyone suggest a definitive, 100-percent reliable way to get the currently launched application's PID?
Or alternatively, is there a way to launch a given file with a specified application such that the application always opens as the frontmost app?
Have you tried using the other version of openFile which will allow you to deactivate your application, allowing the new application to take focus?
[[NSWorkspace sharedWorkspace] openFile:fileName withApplication:appName andDeactivate:YES];
It is definitely not easy to get the PID of an application. And that's how Apple likes it.. Those cheeky bastards.
I had to write this beast just to get the PID from a full path of an app I knew was running.. Hey it's easier than parsing ps aux !
Sorry if there are some of my own private functions in there but you can get the idea of how I went about it and what I tried to avoid along the way.
+ (NSUInteger)pidFromAppPath:(NSString*)path
{
NSRunningApplication *n = [[[NSWorkspace sharedWorkspace]runningApplications] filterOne:^BOOL(NSRunningApplication *runner) {
// optional: avoid totally faceless apps and "Desk Accesory"-type background apps.
if (runner.activationPolicy == NSApplicationActivationPolicyProhibited) ||
runner.activationPolicy == NSApplicationActivationPolicyAccessory)
return nil;
id runPath = [runner valueForKeyPath:#"bundleURL"];
NSString *runString = [runPath isKindOfClass:[NSString class]]
? runPath
: [runPath isKindOfClass:NSURL.class] ? [((NSURL*)runPath) path]
: nil;
// optional: filter out Google Chrome's mockery of a once sane process-table
if ( !runString
|| [[runString lastPathComponent]contains:#"Google Chrome Helper.app"]
|| [[runString lastPathComponent]contains:#"Google Chrome Worker.app"]
|| [[runString lastPathComponent]contains:#"Google Chrome Renderer.app"] )
return nil;
return [runString isEqualToString:path] ?: nil; // This is where you actually test to see if it's the same as the string passed in, lol.
}];
return n ? [n processIdentifier] : 11000; // if 11000 you messed up.
}
And voilá... NSLOG: Pid of /Applications/Utilities/Terminal.app is 46152

ASIHTTPRequestErrorDomain Code=8. Cannot move file from temp directory to docs

I download files with ASIHTTPReqeust. Everything downloads fine but it can't move file from temp directory to documents. When i implement
-(void) request:(ASIHTTPRequest *)request didReceiveData:(NSData *)data
request fails with an error. But file is downloaded.
If i remove this implementation, everything is fine, and files are moving to docs.
Here is Error text:
Error Domain=ASIHTTPRequestErrorDomain Code=8 "Failed to move file from '/var/folders/Qu/Qu0o0VcpEY4npJr2C1yPzE+++TI/-Tmp-/Skrillex feat. Nero - Wobbleland.mp3' to '/Users/Timur/Library/Application Support/iPhone Simulator/4.3/Applications/34389282-4013-4354-95D9-DF2847B4EE55/Documents/Audio/Skrillex feat. Nero - Wobbleland.mp3'" UserInfo=0x5949520 {NSUnderlyingError=0x59992a0 "The operation couldn’t be completed. (Cocoa error 4.)", NSLocalizedDescription=Failed to move file from '/var/folders/Qu/Qu0o0VcpEY4npJr2C1yPzE+++TI/-Tmp-/Skrillex feat. Nero - Wobbleland.mp3' to '/Users/Timur/Library/Application Support/iPhone Simulator/4.3/Applications/34389282-4013-4354-95D9-DF2847B4EE55/Documents/Audio/Skrillex feat. Nero - Wobbleland.mp3'}
Who had similar problem?
Something that often catches people out is that you have to create the directory that you're downloading into yourself (ASIHTTPRequest won't create it automatically).
However given you say it's related to the implementing didReceiveData it's not that.
If you look at ASIHTTPRequest.m, you'll see it sets 'dataWillBeHandledExternally' if you implement 'didReceiveData' in the delegate - this will be preventing the data being written to disk. You can either write the data yourself, or you could change the ASIHTTPRequest.m code to add a flag to force it to handle the data internally too.
I encountered same error, but the reason was different. I will post my problem - just in case anyone else has similar situation.
I was trying to delete old images, before saving new ones.
NSString *mImgName = [managedObj valueForKey:#"aImgName"];
NSString * mFilePath = [[self applicationDocumentsDirectory]
stringByAppendingPathComponent:mImgName];
if ([mFileManager fileExistsAtPath:mFilePath])
{
[mFileManager removeItemAtPath:mFilePath error:nil];
}
Problem was - in case mImgName is nil, mFileManager will delete whole directory.
By adding extra checking for nil or too short mImgName value, it solved problem.
Hopefully it will help someone!