Unique Identifier of a Mac? - cocoa

On an iPhone I can use
[[UIDevice currentDevice] uniqueIdentifier];
to get a string which identifies this device. Is there anything equal in OSX ? I didn't find anything. I just want to identify the Mac which started the application. Can you help me ?

Apple has a technote on uniquely identifying a mac. Here's a loosely modified version of the code Apple has posted in that technote... don't forget to link your project against IOKit.framework in order to build this:
#import <IOKit/IOKitLib.h>
- (NSString *)serialNumber
{
io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault,
IOServiceMatching("IOPlatformExpertDevice"));
CFStringRef serialNumberAsCFString = NULL;
if (platformExpert) {
serialNumberAsCFString = IORegistryEntryCreateCFProperty(platformExpert,
CFSTR(kIOPlatformSerialNumberKey),
kCFAllocatorDefault, 0);
IOObjectRelease(platformExpert);
}
NSString *serialNumberAsNSString = nil;
if (serialNumberAsCFString) {
serialNumberAsNSString = [NSString stringWithString:(NSString *)serialNumberAsCFString];
CFRelease(serialNumberAsCFString);
}
return serialNumberAsNSString;
}

Swift 2 Answer
This answer augments Jarret Hardie's 2011 answer. It's a Swift 2 String extension. I've added inline comments to explain what I did and why, since navigating whether or not an object needs to be released can be tricky here.
extension String {
static func macSerialNumber() -> String {
// Get the platform expert
let platformExpert: io_service_t = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice"));
// Get the serial number as a CFString ( actually as Unmanaged<AnyObject>! )
let serialNumberAsCFString = IORegistryEntryCreateCFProperty(platformExpert, kIOPlatformSerialNumberKey, kCFAllocatorDefault, 0);
// Release the platform expert (we're responsible)
IOObjectRelease(platformExpert);
// Take the unretained value of the unmanaged-any-object
// (so we're not responsible for releasing it)
// and pass it back as a String or, if it fails, an empty string
return (serialNumberAsCFString.takeUnretainedValue() as? String) ?? ""
}
}
Alternatively, the function could return String? and the last line could not return an empty string. That might make it easier to recognize the extreme situations where the serial number could not be retrieved (such as the repaired-Mac-motherboard scenario harrisg mentioned in his comment to Jerret's answer).
I also verified proper memory management with Instruments.
I hope someone finds it useful!

Thanks. Works perfectly after changing
serialNumberAsNSString = [NSString stringWithString:(NSString *)serialNumberAsCFString];
TO
serialNumberAsNSString = [NSString stringWithString:(__bridge NSString *)serialNumberAsCFString];
the __bridge is recommended by Xcode itself.

Related

Does iOS 13 has new way of getting device notification token?

So my friend got this email from OneSignal
Due to a change that may occur as part of the upcoming iOS 13 release, you must update to the latest version of the iOS SDK before building your app with Xcode 11. All of OneSignal’s wrapper SDKs including React Native, Unity, and Flutter have been updated as well.
The reason for this is that Xcode 11, which is being released alongside iOS 13, breaks a common technique that apps and libraries like OneSignal were using to get a push token for the device. If you do not use our new SDK then new users will not be able to subscribe to notifications from your app.
And I got curious about it.
This is the way we got the device notification token on iOS 12
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
var token = ""
for i in 0..<deviceToken.count {
token = token + String(format: "%02.2hhx", arguments: [deviceToken[i]])
}
print("Notification token = \(token)")
}
Whats the proper way to get it on iOS 13?
Should I do the new way for my currently developing apps or the old way is still fine?
You may use this method to fetch the device token on iOS 13 onwards:
Objective-C:
+ (NSString *)stringFromDeviceToken:(NSData *)deviceToken {
NSUInteger length = deviceToken.length;
if (length == 0) {
return nil;
}
const unsigned char *buffer = deviceToken.bytes;
NSMutableString *hexString = [NSMutableString stringWithCapacity:(length * 2)];
for (int i = 0; i < length; ++i) {
[hexString appendFormat:#"%02x", buffer[i]];
}
return [hexString copy];
}
Swift 5.0 (Untested)
class func string(fromDeviceToken deviceToken: Data?) -> String? {
let length = deviceToken?.count ?? 0
if length == 0 {
return nil
}
let buffer = UInt8(deviceToken?.bytes ?? 0)
var hexString = String(repeating: "\0", count: length * 2)
for i in 0..<length {
hexString += String(format: "%02x", buffer[i])
}
return hexString
}
Taken from OneSignal blog
The way you do it is fine and it should continue to work on iOS 13. But some developers do it like this. To convert Data into base-16 strings, they call description, which returns something like
<124686a5 556a72ca d808f572 00c323b9 3eff9285 92445590 3225757d b83997ba>
And then they trim < and > and remove spaces.
On iOS 13 the description called on token data returns something like
{ length = 32, bytes = 0xd3d997af 967d1f43 b405374a 13394d2f ... 28f10282 14af515f }
Which obviously makes this way broken.
Another example of wrong implementation (already edited to include correct implementation as well).
Some more examples might be found in this thread.
The same code for Swift 5 but bit shorter variant. Verified at iOS 13.
func getStringFrom(token:NSData) -> String {
return token.reduce("") { $0 + String(format: "%02.2hhx", $1) }
}
Correctly capture iOS 13 Device Token in Xamarin.iOS
public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
//DeviceToken = Regex.Replace(deviceToken.ToString(), "[^0-9a-zA-Z]+", "");
//Replace the above line whick worked up to iOS12 with the code below:
byte[] bytes = deviceToken.ToArray<byte>();
string[] hexArray = bytes.Select(b => b.ToString("x2")).ToArray();
DeviceToken = string.Join(string.Empty, hexArray);
}
Here is what's going on here:
First we have to grab all the bytes in the device token by calling
the ToArray() method on it.
Once we have the bytes which is an array of bytes or, byte[], we
call LINQ Select which applies an inner function that takes each
byte and returns a zero-padded 2 digit Hex string. C# can do this
nicely using the format specifier x2. The LINQ Select function
returns an IEnumerable, so it’s easy to call ToArray() to
get an array of string or string[].
Now just call Join() method on an array of string and we end up with
a concatenated string.
Reference: https://dev.to/codeprototype/correctly-capture-ios-13-device-token-in-xamarin-1968
Solution 2: This also works fine
public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
byte[] result = new byte[deviceToken.Length];
Marshal.Copy(deviceToken.Bytes, result, 0, (int)deviceToken.Length);
var token = BitConverter.ToString(result).Replace("-", "");
}
Nice solution in C# with Xamarin:
// In AppDelegate class:
public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
var bytes = deviceToken.ToArray();
var deviceTokenString = string.Concat(bytes.Select(b => $"{b:x2}"));
// TODO: handle deviceTokenString
}
func getStringFrom(deviceToken: Data) -> String {
var token = ""
for i in 0..<deviceToken.count {
token += String(format: "%02.2hhx", arguments: [deviceToken[i]])
}
return token
}
You can have look in the below code as I was also stuck on this problem. Here is the code by which you can get the device token in below iOS 13 and above.
NSString *str = [NSString stringWithFormat:#"%#", devTokendata]; // devTokendata is NSData
str = [str stringByReplacingOccurrencesOfString:#" " withString:#""];
str = [str stringByReplacingOccurrencesOfString:#"<" withString:#""];
str = [str stringByReplacingOccurrencesOfString:#">" withString:#""];
if (#available(iOS 13, *)) {
str = [self hexadecimalStringFromData:devToken];
NSLog(#"APNS Token: %#",str);
}
-(NSString *)deviceTokenFromData:(NSData *)data
{
NSUInteger dataLength = data.length;
if (dataLength == 0) {
return nil;
}
const unsigned char *dataBuffer = (const unsigned char *)data.bytes;
NSMutableString *hexString = [NSMutableString stringWithCapacity:(dataLength * 2)];
for (int i = 0; i < dataLength; ++i) {
[hexString appendFormat:#"%02x", dataBuffer[i]];
}
return [hexString copy];
}
use deviceToken.debugDescription

How to read Finder icons (left source list) on OS X using Swift

I try to read information about icons that are shown in finder on left source list. I tried already NSFileManager with following options
NSURLEffectiveIconKey icon read is not the same as in finder
NSURLCustomIconKey - returns nil
NSURLThumbnailKey - returns nil
NSThumbnail1024x1024SizeKey - returns nil
I managed to read all mounted devices using NSFileManager but I have no clue how to read icons connected with devices? Maybe someone has any idea or a hint.
I also tried to use
var image: NSImage = NSWorkspace.sharedWorkspace().iconForFile((url as! NSURL).path!)
but it returns the same image as NSURLEffectiveIconKey
Thanks!
First, the proper way to query which volumes are shown in the Finder's sidebar is using the LSSharedFileList API. That API also provides a way to query the icon:
LSSharedFileListRef list = LSSharedFileListCreate(NULL, kLSSharedFileListFavoriteVolumes, NULL);
UInt32 seed;
NSArray* items = CFBridgingRelease(LSSharedFileListCopySnapshot(list, &seed));
CFRelease(list);
for (id item in items)
{
IconRef icon = LSSharedFileListItemCopyIconRef((__bridge LSSharedFileListItemRef)item);
NSImage* image = [[NSImage alloc] initWithIconRef:icon];
// Do something with this item and icon
ReleaseIconRef(icon);
}
You can query other properties of the items using LSSharedFileListItemCopyDisplayName(), LSSharedFileListItemCopyResolvedURL, and LSSharedFileListItemCopyProperty().
This answer is a translation to Swift 1.2 of Ken Thomases's Objective-C answer.
All credits go to Ken Thomases, this is just a translation of his awesome answer.
let listBase = LSSharedFileListCreate(kCFAllocatorDefault, kLSSharedFileListFavoriteVolumes.takeUnretainedValue(), NSMutableDictionary())
let list = listBase.takeRetainedValue() as LSSharedFileList
var seed:UInt32 = 0
let itemsCF = LSSharedFileListCopySnapshot(list, &seed)
if let items = itemsCF.takeRetainedValue() as? [LSSharedFileListItemRef] {
for item in items {
let icon = LSSharedFileListItemCopyIconRef(item)
let image = NSImage(iconRef: icon)
// use image ...
}
}
Explanations:
When translating Ken's answer from Objective-C to try and use it I encountered some difficulties, this is the reason why I made this answer.
First problem was with LSSharedFileListCreate, the method signature in Swift didn't accept nil as its first parameter. I had to find a constant representing a CFAllocator: kCFAllocatorDefault. And the third parameter didn't accept nil either, so I put a dummy unused NSMutableDictionary to keep the compiler happy.
Also the "seed" parameter for LSSharedFileListCopySnapshot didn't accept the usual var seed:Uint32? for the inout, I had to give a default value to seed.
For deciding when to use takeRetainedValue or takeUnRetainedValue when using these APIs I referred to this answer.
Last, I had to cast the returned array as a Swift array of LSSharedFileListItemRef elements (it was initially inferred as a CFArray by the compiler).
Update
This has been deprecated in OS X El Capitan 10.11 (thanks #patmar)
Update 2
Note that while it's been deprecated it still works. The cast as [LSSharedFileListItemRef] in the previous solution is now ignored so we have to cast as NSArray instead then cast the item later:
if let items = itemsCF.takeRetainedValue() as? NSArray {
for item in items {
let icon = LSSharedFileListItemCopyIconRef(item as! LSSharedFileListItem)
let image = NSImage(iconRef: icon)
// use image ...
}
}
NSURLCustomIconKey will return nil because support for this key is not implemented. It's mentioned in the header but not in the NSURL documentation. You could get the info via deprecated File Manager methods.
https://developer.apple.com/library/mac/documentation/Carbon/Reference/File_Manager/
Alternatively maybe something like this.
func getResourceValue(_ value: AutoreleasingUnsafeMutablePointer<AnyObject?>,
forKey key: String,
error error: NSErrorPointer) -> Bool
Parameters
value
The location where the value for the resource property identified by key should be stored.
key
The name of one of the URL’s resource properties.
error
The error that occurred if the resource value could not be retrieved. This parameter is optional. If you are not interested in receiving error information, you can pass nil.
2022, swift 5
low-res icon (really fast work):
let icon: NSImage = NSWorkspace.shared.icon(forFile: url.path )
Hi-res icon:
extension NSWorkspace {
func highResIcon(forPath path: String, resolution: Int = 512) -> NSImage {
if let rep = self.icon(forFile: path)
.bestRepresentation(for: NSRect(x: 0, y: 0, width: resolution, height: resolution), context: nil, hints: nil) {
let image = NSImage(size: rep.size)
image.addRepresentation(rep)
return image
}
return self.icon(forFile: path)
}
}
Also hi-res thumbnail:
fileprivate extension URL {
func getImgThumbnail(_ size: CGFloat) -> NSImage? {
let ref = QLThumbnailCreate ( kCFAllocatorDefault,
self as NSURL,
CGSize(width: size, height: size),
[ kQLThumbnailOptionIconModeKey: false ] as CFDictionary
)
guard let thumbnail = ref?.takeRetainedValue()
else { return nil }
if let cgImageRef = QLThumbnailCopyImage(thumbnail) {
let cgImage = cgImageRef.takeRetainedValue()
return NSImage(cgImage: cgImage, size: CGSize(width: cgImage.width, height: cgImage.height))
}
return nil
}
}

Obtain Model Identifier string on OS X

Every Mac has a model identifier, for example "Macmini5,1". (These are shown in the System Information app.)
How can I programatically obtain this model identifier string?
Swift 4+ using IOKit
import IOKit
func getModelIdentifier() -> String? {
let service = IOServiceGetMatchingService(kIOMasterPortDefault,
IOServiceMatching("IOPlatformExpertDevice"))
var modelIdentifier: String?
if let modelData = IORegistryEntryCreateCFProperty(service, "model" as CFString, kCFAllocatorDefault, 0).takeRetainedValue() as? Data {
modelIdentifier = String(data: modelData, encoding: .utf8)?.trimmingCharacters(in: .controlCharacters)
}
IOObjectRelease(service)
return modelIdentifier
}
You can use sysctl
#import <Foundation/Foundation.h>
#import <sys/sysctl.h>
NSString *ModelIdentifier()
{
NSString *result=#"Unknown Mac";
size_t len=0;
sysctlbyname("hw.model", NULL, &len, NULL, 0);
if (len) {
NSMutableData *data=[NSMutableData dataWithLength:len];
sysctlbyname("hw.model", [data mutableBytes], &len, NULL, 0);
result=[NSString stringWithUTF8String:[data bytes]];
}
return result;
}
You can also use IOKit.framework. I think it's best choice.
This simple code example shows how to read model identifier from I/O Kit registry to NSString:
- (NSString *)modelIdentifier {
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault,
IOServiceMatching("IOPlatformExpertDevice"));
CFStringRef model = IORegistryEntryCreateCFProperty(service,
CFSTR("model"),
kCFAllocatorDefault,
0);
NSString *modelIdentifier = [[NSString alloc] initWithData:(__bridge NSData *)model
encoding:NSUTF8StringEncoding];
CFRelease(model);
IOObjectRelease(service);
return modelIdentifier;
}
Strings "IOPlatformExpertDevice" and "model" in code above is used to read model identifier from I/O Kit registry. ioreg command line tool is your friend, when you want to find information from I/O Kit registry. This image shows those strings in ioreg output:
I hope this helps to use IOKit.framework.
Answer from Ryan H is correct except improper conversion from null-terminated string to Swift String, giving result with \0 symbol in the end, which you may not expect, performing full match. This is corrected version:
static private func modelIdentifier() -> String? {
let service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice"))
defer { IOObjectRelease(service) }
if let modelData = IORegistryEntryCreateCFProperty(service, "model" as CFString, kCFAllocatorDefault, 0).takeRetainedValue() as? Data {
return modelData.withUnsafeBytes { (cString: UnsafePointer<UInt8>) -> String in
return String(cString: cString)
}
}
return nil
}
You can get the same output from the system_profiler command. It has an -xml option that you can use. NSTask can run the command for you and you can parse the result.
Sample code:
#import <Foundation/Foundation.h>
NSString *ModelIdentifier() {
NSPipe *pipe=[NSPipe pipe];
NSTask *task=[[NSTask alloc] init];
[task setLaunchPath:#"/usr/sbin/system_profiler"];
[task setArguments:#[#"-xml", #"SPHardwareDataType"]];
[task setStandardOutput:pipe];
[task launch];
NSData *outData=[[pipe fileHandleForReading] readDataToEndOfFile];
NSString *outString=[[NSString alloc] initWithData:outData encoding:NSUTF8StringEncoding];
return [outString propertyList][0][#"_items"][0][#"machine_model"];
}
CFStringRef model = IORegistryEntryCreateCFProperty(service,
CFSTR("model"),
kCFAllocatorDefault,
0); ? type is ok ?
I think code maybe like this:
CFSDataRef model = IORegistryEntryCreateCFProperty(service,
CFSTR("model"),
kCFAllocatorDefault,
0);
With iOS 16 apps that also build to Mac Catalyst any solution here that uses kIOMasterPortDefault (such as Ryan H's) will generate a build error:
'kIOMasterPortDefault' is unavailable in Mac Catalyst
Attempting to switch kIOMasterPortDefault to kIOMainPortDefault may also give a build error depending on which versions of Catalyst you are targetting – and I found trying to use #available to get around that didn't work either.
If you run into that situation then try the following, which is a reformulation of Parag Bafna's answer into Swift:
var modelIdentifier: String {
#if targetEnvironment(macCatalyst)
var size = 0
sysctlbyname("hw.model", nil, &size, nil, 0)
var modelIdentifier: [CChar] = Array(repeating: 0, count: size)
sysctlbyname("hw.model", &modelIdentifier, &size, nil, 0)
return String(cString: modelIdentifier)
#else
// Handle iOS
#endif
}
Swift version of Parag Bafna excellent answer
var deviceName: String {
var str = "Unknown Device"
var len = 0
sysctlbyname("hw.model", nil, &len, nil, 0)
if len > 0 {
var data = Data(count: len)
sysctlbyname("hw.model", &data, &len, nil, 0)
if let s = String(bytes: data, encoding: .utf8) {
str = s
}
}
return str
}

Execute Applescript from Cocoa App with params

I would like to know how to execute an applescript from a cocoa application passing parameters.
I have seen how easy is to execute applescripts with no parameters in other questions here at stackoverflow, however the use NSAppleScript class, in which, i haven't seen no method that solve my problem. Does anyone have any idea.
I would like a Cocoa code with the same effect o this shell:
osascript teste.applescript "snow:Users:MyUser:Desktop:MyFolder" "snow:Users:MyUser:Desktop:Example:"
So it may run this AppleScript.
on run argv
set source to (item 1 of argv)
set destiny to (item 2 of argv)
tell application "Finder" to make new alias file at destiny to source
0
end run
Any help is appreciated. Thanks in advance.
Look at my GitHub repository, I have a category of NSAppleEventDescriptor that makes it much easier to create NSAppleEventDescriptor to call different AppleScript procedures with arguments, and coercion to and from many AppleScript typed.
NSAppleEventDescriptor-NDCoercion
I found easier to follow this piece code. I took a code from here and modified it to my purpose.
- (BOOL) executeScriptWithPath:(NSString*)path function:(NSString*)functionName andArguments:(NSArray*)scriptArgumentArray
{
BOOL executionSucceed = NO;
NSAppleScript * appleScript;
NSAppleEventDescriptor * thisApplication, *containerEvent;
NSURL * pathURL = [NSURL fileURLWithPath:path];
NSDictionary * appleScriptCreationError = nil;
appleScript = [[NSAppleScript alloc] initWithContentsOfURL:pathURL error:&appleScriptCreationError];
if (appleScriptCreationError)
{
NSLog([NSString stringWithFormat:#"Could not instantiate applescript %#",appleScriptCreationError]);
}
else
{
if (functionName && [functionName length])
{
/* If we have a functionName (and potentially arguments), we build
* an NSAppleEvent to execute the script. */
//Get a descriptor for ourself
int pid = [[NSProcessInfo processInfo] processIdentifier];
thisApplication = [NSAppleEventDescriptor descriptorWithDescriptorType:typeKernelProcessID
bytes:&pid
length:sizeof(pid)];
//Create the container event
//We need these constants from the Carbon OpenScripting framework, but we don't actually need Carbon.framework...
#define kASAppleScriptSuite 'ascr'
#define kASSubroutineEvent 'psbr'
#define keyASSubroutineName 'snam'
containerEvent = [NSAppleEventDescriptor appleEventWithEventClass:kASAppleScriptSuite
eventID:kASSubroutineEvent
targetDescriptor:thisApplication
returnID:kAutoGenerateReturnID
transactionID:kAnyTransactionID];
//Set the target function
[containerEvent setParamDescriptor:[NSAppleEventDescriptor descriptorWithString:functionName]
forKeyword:keyASSubroutineName];
//Pass arguments - arguments is expecting an NSArray with only NSString objects
if ([scriptArgumentArray count])
{
NSAppleEventDescriptor *arguments = [[NSAppleEventDescriptor alloc] initListDescriptor];
NSString *object;
for (object in scriptArgumentArray) {
[arguments insertDescriptor:[NSAppleEventDescriptor descriptorWithString:object]
atIndex:([arguments numberOfItems] + 1)]; //This +1 seems wrong... but it's not
}
[containerEvent setParamDescriptor:arguments forKeyword:keyDirectObject];
[arguments release];
}
//Execute the event
NSDictionary * executionError = nil;
NSAppleEventDescriptor * result = [appleScript executeAppleEvent:containerEvent error:&executionError];
if (executionError != nil)
{
NSLog([NSString stringWithFormat:#"error while executing script. Error %#",executionError]);
}
else
{
NSLog(#"Script execution has succeed. Result(%#)",result);
executionSucceed = YES;
}
}
else
{
NSDictionary * executionError = nil;
NSAppleEventDescriptor * result = [appleScript executeAndReturnError:&executionError];
if (executionError != nil)
{
NSLog([NSString stringWithFormat:#"error while executing script. Error %#",executionError]);
}
else
{
NSLog(#"Script execution has succeed. Result(%#)",result);
executionSucceed = YES;
}
}
}
[appleScript release];
return executionSucceed;
}
Technical Note TN2084
Using AppleScript Scripts in Cocoa Applications
Even though your application is written in Objective-C using Cocoa, you can use AppleScript scripts to perform certain operations. This Technical Note explains how to integrate and execute AppleScripts from within your Cocoa application. It discusses how to leverage the NSAppleScript class and the use of NSAppleEventDescriptor to send data to the receiver.
https://developer.apple.com/library/archive/technotes/tn2084/_index.html
https://applescriptlibrary.files.wordpress.com/2013/11/technical-note-tn2084-using-applescript-scripts-in-cocoa-applications.pdf
Swift 4 version, modified from the code here:
https://gist.github.com/chbeer/3666e4b7b2e71eb47b15eaae63d4192f
import Carbon
static func runAppleScript(_ url: URL) {
var appleScriptError: NSDictionary? = nil
guard let script = NSAppleScript(contentsOf: url, error: &appleScriptError) else {
return
}
let message = NSAppleEventDescriptor(string: "String parameter")
let parameters = NSAppleEventDescriptor(listDescriptor: ())
parameters.insert(message, at: 1)
var psn = ProcessSerialNumber(highLongOfPSN: UInt32(0), lowLongOfPSN: UInt32(kCurrentProcess))
let target = NSAppleEventDescriptor(descriptorType: typeProcessSerialNumber, bytes: &psn, length: MemoryLayout<ProcessSerialNumber>.size)
let handler = NSAppleEventDescriptor(string: "MyMethodName")
let event = NSAppleEventDescriptor.appleEvent(withEventClass: AEEventClass(kASAppleScriptSuite), eventID: AEEventID(kASSubroutineEvent), targetDescriptor: target, returnID: AEReturnID(kAutoGenerateReturnID), transactionID: AETransactionID(kAnyTransactionID))
event.setParam(handler, forKeyword: AEKeyword(keyASSubroutineName))
event.setParam(parameters, forKeyword: AEKeyword(keyDirectObject))
var executeError: NSDictionary? = nil
script.executeAppleEvent(event, error: &executeError)
if let executeError = executeError {
print("ERROR: \(executeError)")
}
}
For running the apple script:
on MyMethodName(theParameter)
display dialog theParameter
end MyMethodName
I'm not all too familiar with AppleScript, but I seem to remember that they are heavily based on (the rather crappy) Apple Events mechanism which dates back to the days where the 56k Modem was the coolest Gadget in your house.
Therefore I'd guess that you're looking for executeAppleEvent:error: which is part of NSAppleScript. Maybe you can find some information on how to encapsulate execution arguments in the instance of NSAppleEventDescriptor that you have to pass along with this function.

(MACOSX) - Knowing whether a mounted device was mounted from a DMG

Couldn't find that info using DiskArbitration or FSGetVolumeInfo/GetVolumeParms...
I know that hdiutil uses a private framework called DiskImages framework, but I wouldn't want to run an external utility each time I want this info... wheres the API for this ?
July 2015 Update
This update was prompted by Stan James' new question.
You can obtain this information using the DiskArbitration framework. To use the example below, you must link against and #import it.
#import <DiskArbitration/DiskArbitration.h>
...
- (BOOL)isDMGVolumeAtURL:(NSURL *)url
{
BOOL isDMG = NO;
if (url.isFileURL) {
DASessionRef session = DASessionCreate(kCFAllocatorDefault);
if (session != nil) {
DADiskRef disk = DADiskCreateFromVolumePath(kCFAllocatorDefault, session, (__bridge CFURLRef)url);
if (disk != nil) {
NSDictionary * desc = CFBridgingRelease(DADiskCopyDescription(disk));
NSString * model = desc[(NSString *)kDADiskDescriptionDeviceModelKey];
isDMG = ([model isEqualToString:#"Disk Image"]);
CFRelease(disk);
}
CFRelease(session);
}
}
return isDMG;
}
Usage:
BOOL isDMG = [someObject isDMGVolumeAtURL:[NSURL fileURLWithPath:#"/Volumes/Some Volume"]];
I hope this helps.

Resources