Find Mac OS X version number in objective c - objective-c

How can I find the version number of Mac OS X (eg. "10.6.7") from my Cocoa Objective-C application?

#import <CoreServices/CoreServices.h>
SInt32 major, minor, bugfix;
Gestalt(gestaltSystemVersionMajor, &major);
Gestalt(gestaltSystemVersionMinor, &minor);
Gestalt(gestaltSystemVersionBugFix, &bugfix);
NSString *systemVersion = [NSString stringWithFormat:#"%d.%d.%d",
major, minor, bugfix];

You could use the same technique that Apple's code uses...
NSDictionary *systemVersionDictionary =
[NSDictionary dictionaryWithContentsOfFile:
#"/System/Library/CoreServices/SystemVersion.plist"];
NSString *systemVersion =
[systemVersionDictionary objectForKey:#"ProductVersion"];
Apple does exactly this to fill in the version number for various system utilities in the function _CFCopySystemVersionDictionary here:
http://opensource.apple.com/source/CF/CF-744/CFUtilities.c

For OS X 10.10+ I think using NSProcessInfo is an easier and safer way to do that:
NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion];
NSLog([NSString stringWithFormat:#"%ld.%ld.%ld", version.majorVersion, version.minorVersion, version.patchVersion]);

Related

unicode assignment failing in NSString?

The following fails for both unichar assignments?
unsigned int c = 0x0001d122;
[NSString stringWithFormat:#"\U%#", [NSString stringWithFormat:#"%08X", c]];
[NSString stringWithFormat:#"\U%08X", c];
I am trying to do this programmatically (adding in the "\U" makes things difficult as seen above):
nssSymbol = #"\U0001d122"; \\this works... but need to be able to vary 'c'
As shown by Ken Thomases answer you can create a string from bytes, however you must know the endianness of your machine or use the endian conversion routines.
For example, on an Intel Mac which is little endian you can use:
uint32_t c = 0x0001d122;
NSString* s = [[NSString alloc] initWithBytes:&c
length:sizeof(c)
encoding:NSUTF32LittleEndianStringEncoding];
If you don't wish to code in knowledge of the systems endianness you can use the conversion routines. For example:
uint32_t c = EndianU32_NtoB(0x0001d122); // convert from native endianness to big endian
NSString* s = [[NSString alloc] initWithBytes:&c
length:sizeof(c)
encoding:NSUTF32BigEndianStringEncoding];
HTH
The handling of the \Unnnnnnnn construct in a string literal is done at compile time. You can't build the construct at run time and have it interpreted. That's not how things work.
You could do:
uint32_t c = 0x0001d122;
NSString* s = [[NSString alloc] initWithBytes:&c length:sizeof(c) encoding:NSUTF32LittleEndianStringEncoding];

Get OSX version with objective-c

How would I be able to get the OSX version in objective-c? I would like to avoid using shell commands. E.g "10.5" or "10.4"
NSProcessInfo *pInfo = [NSProcessInfo processInfo];
NSString *version = [pInfo operatingSystemVersionString];
Sorry for the formatting, I'm using my iPad to answer this.
As of 10.10 you can use NSProcessInfo.processInfo.operatingSystemVersion to get a NSOperatingSystemVersion struct.
typedef struct {
NSInteger majorVersion;
NSInteger minorVersion;
NSInteger patchVersion;
} NSOperatingSystemVersion;
There's also a helpful isOperatingSystemAtLeastVersion: method.
NSOperatingSystemVersion minimumSupportedOSVersion = { .majorVersion = 10, .minorVersion = 12, .patchVersion = 0 };
BOOL isSupported = [NSProcessInfo.processInfo isOperatingSystemAtLeastVersion:minimumSupportedOSVersion];
You can parse it in this way to get the format you want:
NSProcessInfo *pinfo = [NSProcessInfo processInfo];
NSArray *myarr = [[pinfo operatingSystemVersionString] componentsSeparatedByString:#" "];
NSString *version = [#"Mac OS X " stringByAppendingString:[myarr objectAtIndex:1]];
This f.e. will give you Mac OS X 10.6.8
You can use the Gestalt function to access the components of the OS version.
Old-time users of Gestalt may be amazed to find that it is still available in 64-bit.
See this response using NSAppKitVersionNumber in case you're using AppKit in your app as well (and want to run on 10.8+ as Gestalt is now deprecated):
How to know what Mac OS the app is running on?
add this code after #import
#define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
after adding above code please add below code where you want to see your os-version
NSString *systemVersion = [[UIDevice currentDevice] systemVersion];
NSLog(#"System version :%#",systemVersion);
you can easily get OS-version by above code
Thank you

#"" string type literals for NSNumber

I love the shorthand handling of string literals in Objective C with the #"string" notation. Is there any way to get similar behavior with NSNumbers? I deal with numbers more and it's so tedious having [NSNumber numberWithWhatever:] calls everywhere. Even creating a macro would work, but my knowledge of how best to do that is limited.
Since nobody has mentioned this... If you need to wrap a value in an NSNumber, the NSNumber literal syntax is as follows.
int val = 13;
NSNumber *numVal = #(val);
As of Clang v3.1 you can now use Objective-C literals.
NSNumber *fortyTwo = #42; // equivalent to [NSNumber numberWithInt:42]
NSNumber *fortyTwoUnsigned = #42U; // equivalent to [NSNumber numberWithUnsignedInt:42U]
NSNumber *fortyTwoLong = #42L; // equivalent to [NSNumber numberWithLong:42L]
NSNumber *fortyTwoLongLong = #42LL; // equivalent to [NSNumber numberWithLongLong:42LL]
So, answering your specific question:
[Tyler setArms:[[[NSNumber alloc] initWithInt:1] autorelease]];
Can now be written as:
[Tyler setArms:#1];
There are also literals for arrays and dictionaries, but they are beyond the scope of this question.
To take advantage of literals in Xcode you'll need at least version 4.4 -- this comes with Apple's LLVM 4.0 compiler.
I'm using a macro like
#define N(x) [NSNumber numberWithInt: x]
wich leads to code like
[N(123) intValue];
update:
One should be aware of the CPU and memory consumption of such a macro. While the #"…" strings are static compiler generated strings of the constant string class (depends on foundation maybe NSConstantString in Cocoa?) the macros create code which is evaluated at runtime and therefore create a new object every time they are called.
Xcode 4.4 has introduced the Clang features that rjstelling mentioned for literals for NSNumber, NSArray and NSDictionary. The syntax is simple:
//Number literal
NSNumber *pi = #3.14;
//Array literal
NSArray *primes = #[ #2, #3, #5, #7, #11 ]; //No nil terminator needed
//Dictionary literal
NSDictionary *dict = #{
#"key1": #42,
#"key2": #"Another key",
#3: #"A NSNumber key"
}; //No nil terminator, stored in "key:value," format

What is the simplest implementation of Markdown for a Cocoa application?

I'm writing a Cocoa application in Objective-C, and I would like to be able to incorporate Markdown. The user will enter text in Markdown syntax, click an "export" button, and the program will output a file of XHTML.
It seems like there are a lot of options, though. I could use one of the C/C++ implementations, I could run the Perl script as a resource to my Cocoa app, I assume could use the Python implementation and the PyObjC bridge or the Perl implementation and the CamelBones or PerlObjC bridges. What would be the simplest and easiest solution? I'm not doing anything complicated like a real-time rendered preview that would require threading.
I had a look at the various options, and in the end found libsoldout, a very small C implementation that's quite easy to integrate. You just need to include array.[ch], buffer.[ch], markdown.[ch], and renderers.[ch] in your Xcode project, then you can convert an NSString from markdown to HTML like so:
NSString *rawMarkdown;
const char * prose = [rawMarkdown UTF8String];
struct buf *ib, *ob;
int length = rawMarkdown.length + 1;
ib = bufnew(length);
bufgrow(ib, length);
memcpy(ib->data, prose, length);
ib->size = length;
ob = bufnew(64);
markdown(ob, ib, &mkd_xhtml);
NSString *shinyNewHTML = [NSString stringWithUTF8String: ob->data];
NSLog(#"%#", shinyNewHTML);
bufrelease(ib);
bufrelease(ob);
I just used the Sundown implementation which includes SmartyPants support, in an iPad app with great success. Took about 15 minutes to build a test app.
Assume you have a UITextView *textView (which you setDelegate:self) and also a UIWebView *webView in which to display the results:
- (void) textViewDidEndEditing:(UITextView *)textView
{
NSString *rawMarkdown = [textView text];
const char * prose = [rawMarkdown UTF8String];
struct buf *ib, *ob;
int length = [rawMarkdown lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1;
ib = bufnew(length);
bufgrow(ib, length);
memcpy(ib->data, prose, length);
ib->size = length;
ob = bufnew(64);
struct sd_callbacks callbacks;
struct html_renderopt options;
struct sd_markdown *markdown;
sdhtml_renderer(&callbacks, &options, 0);
markdown = sd_markdown_new(0, 16, &callbacks, &options);
sd_markdown_render(ob, ib->data, ib->size, markdown);
sd_markdown_free(markdown);
NSString *shinyNewHTML = [NSString stringWithUTF8String: ob->data];
[webView loadHTMLString:shinyNewHTML baseURL:[[NSURL alloc] initWithString:#""]];
bufrelease(ib);
bufrelease(ob);
}
You may want to check out the open-source app Macdown which I wrote (or alternatively rentzsch's Markdownlive), which incorporate this functionality as the sole purpose of the two apps.
I found problems with processing large amounts of markdown with these C-based libraries.
There's a very simple Obj-C library that worked for me here:
https://github.com/mdiep/MMMarkdown
Steps to use MMMarkdown:
Build the OS X or iOS target
Copy include/MMMarkdown.h and either
lib/libMMMarkdown-Mac.a or lib/libMMMarkdown-iOS.a into your project
Then the code is:
#import "MMMarkdown.h"
NSError *error;
NSString *markdown = #"# Example\nWhat a library!";
NSString *htmlString = [MMMarkdown HTMLStringWithMarkdown:markdown error:&error];
// Returns #"<h1>Example</h1>\n<p>What a library!</p>"
I've used peg-markdown, it's much faster than the original perl and can handle a few syntax extensions if you enable them.
Oliver Letterer's GHMarkdownParser translate markdown to HTML.
Phil Toland's QLMarkdown QuickLook generator for markdown files.

How do I create a temporary file with Cocoa?

Years ago when I was working with C# I could easily create a temporary file and get its name with this function:
Path.GetTempFileName();
This function would create a file with a unique name in the temporary directory and return the full path to that file.
In the Cocoa API's, the closest thing I can find is:
NSTemporaryDirectory
Am I missing something obvious or is there no built in way to do this?
A safe way is to use mkstemp(3).
[Note: This applies to the iPhone SDK, not the Mac OS SDK]
From what I can tell, these functions aren't present in the SDK (the unistd.h file is drastically pared down when compared to the standard Mac OS X 10.5 file). I would use something along the lines of:
[NSTemporaryDirectory() stringByAppendingPathComponent: [NSString stringWithFormat: #"%.0f.%#", [NSDate timeIntervalSinceReferenceDate] * 1000.0, #"txt"]];
Not the prettiest, but functional
Apple has provided an excellent way for accessing temp directory and creating unique names for the temp files.
- (NSString *)pathForTemporaryFileWithPrefix:(NSString *)prefix
{
NSString * result;
CFUUIDRef uuid;
CFStringRef uuidStr;
uuid = CFUUIDCreate(NULL);
assert(uuid != NULL);
uuidStr = CFUUIDCreateString(NULL, uuid);
assert(uuidStr != NULL);
result = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:#"%#-%#", prefix, uuidStr]];
assert(result != nil);
CFRelease(uuidStr);
CFRelease(uuid);
return result;
}
LINK :::: http://developer.apple.com/library/ios/#samplecode/SimpleURLConnections/Introduction/Intro.html#//apple_ref/doc/uid/DTS40009245
see file :::AppDelegate.m
I created a pure Cocoa solution by way of a category on NSFileManager that uses a combination of NSTemporary() and a globally unique ID.
Here the header file:
#interface NSFileManager (TemporaryDirectory)
-(NSString *) createTemporaryDirectory;
#end
And the implementation file:
#implementation NSFileManager (TemporaryDirectory)
-(NSString *) createTemporaryDirectory {
// Create a unique directory in the system temporary directory
NSString *guid = [[NSProcessInfo processInfo] globallyUniqueString];
NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:guid];
if (![self createDirectoryAtPath:path withIntermediateDirectories:NO attributes:nil error:nil]) {
return nil;
}
return path;
}
#end
This creates a temporary directory but could be easily adapted to use createFileAtPath:contents:attributes: instead of createDirectoryAtPath: to create a file instead.
If targeting iOS 6.0 or Mac OS X 10.8 or higher:
NSString *tempFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[[NSUUID UUID] UUIDString]];
Swift 5 and Swift 4.2
import Foundation
func pathForTemporaryFile(with prefix: String) -> URL {
let uuid = UUID().uuidString
let pathComponent = "\(prefix)-\(uuid)"
var tempPath = URL(fileURLWithPath: NSTemporaryDirectory())
tempPath.appendPathComponent(pathComponent)
return tempPath
}
let url = pathForTemporaryFile(with: "blah")
print(url)
// file:///var/folders/42/fg3l5j123z6668cgt81dhks80000gn/T/johndoe.KillerApp/blah-E1DCE512-AC4B-4EAB-8838-547C0502E264
Or alternatively Ssswift's oneliner:
let prefix = "blah"
let url2 = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("\(prefix)-\(UUID())")
print(url2)
You could use mktemp to get a temp filename.
The modern way to do this is FileManager's url(for:in:appropriateFor:create:).
With this method, you can specify a SearchPathDirectory to say exactly what kind of temporary directory you want. For example, a .cachesDirectory will persist between runs (as possible) and be saved in the user's library, while a .itemReplacementDirectory will be on the same volume as the target file.
Don't use legacy APIs like NSTemporaryDirectory, get a proper URL instead from FileManager.
let tmpURL = FileManager
.default
.temporaryDirectory
.appendingPathComponent(UUID().uuidString)
You'd still have to create the directory.
You could use an NSTask to uuidgen to get a unique file name, then append that to a string from NSTemporaryDirectory(). This won't work on Cocoa Touch. It is a bit long-winded though.
Adding to #Philipp:
- (NSString *)createTemporaryFile:(NSData *)contents {
// Create a unique file in the system temporary directory
NSString *guid = [[NSProcessInfo processInfo] globallyUniqueString];
NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:guid];
if(![self createFileAtPath:path contents:contents attributes:nil]) {
return nil;
}
return path;
}