Skip to content

Lessons Learned

sh95014 edited this page Feb 17, 2022 · 13 revisions

General

What's an easy way to log calls to a method?

NSLog(@"%s", __PRETTY_FUNCTION__);

How do I read a property in Info.plist?

[[[NSBundle mainBundle] infoDictionary] objectForKey:@"..."]

How do I filter out multi-byte characters from a string?

[string enumerateSubstringsInRange:NSMakeRange(0, string.length)
                           options:NSStringEnumerationByComposedCharacterSequences
                        usingBlock:^(NSString * _Nullable substring, NSRange substringRange, NSRange enclosingRange, BOOL * _Nonnull stop) {
    // filter out multi-byte characters
    if (substringRange.length == 1) {

How do I get the name of the app?

[NSRunningApplication currentApplication].localizedName

How do I play a system sound?

[[NSSound soundNamed:@"Blow"] play];

How do I time an event precisely?

clock_gettime_nsec_np(CLOCK_UPTIME_RAW)

What's actually required to make a help page?

Here's a good step-by-step tutorial, and here is where I finally got search to work.

Why is the Help page just blank?

Apparently helpd only observes a few directories to update its index, and Xcode build output directories aren't included. Copy the binary to /Applications.

Cocoa

How do I load a SF Symbol?

[NSImage imageWithSystemSymbolName:@"..." accessibilityDescription:@""]

How do I convert a bitmap into a PNG?

NSImage *image = [[NSImage alloc] initWithData:[NSData dataWithBytes:buffer length:bufferSize]];
CGImageRef cgRef = [image CGImageForProposedRect:NULL context:nil hints:nil];
NSBitmapImageRep *newRep = [[NSBitmapImageRep alloc] initWithCGImage:cgRef];
[newRep setSize:[image size]];
NSData *pngData = [newRep representationUsingType:NSBitmapImageFileTypePNG properties:@{}];

How do I duplicate a NSView based on a template?

NSError *error;
NSView *templateView;
NSData *archive = [NSKeyedArchiver archivedDataWithRootObject:templateView requiringSecureCoding:NO error:&error];
...
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:archive error:&error];
unarchiver.requiresSecureCoding = NO;
NSView *duplicateView = [unarchiver decodeObjectForKey:NSKeyedArchiveRootObjectKey];

How do I kill the app when the last window is closed?

- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender {
    return YES;
}

How do I restrict what types of files NSOpenPanel can open?

- (BOOL)panel:(id)sender shouldEnableURL:(NSURL *)url;

Where can I store some context in an NSMenuItem?

Use NSMenuItem's representedObject

How do I make a window resize based on the contents of its panes, such as in preferences?

- (void)viewDidLoad {
    ...
    self.preferredContentSize = self.view.frame.size;

How do I not actually destroy a window when the user clicks the close button?

- (BOOL)windowShouldClose:(NSWindow *)sender {
    [self.window orderOut:sender];
    return NO;
}

How do I instantiate the contents of a xib file?

[[NSBundle mainBundle] loadNibNamed:@"About" owner:self topLevelObjects:nil]

How do I instantiate the contents of a storyboard?

NSStoryboard *storyboard = [NSStoryboard storyboardWithName:@"..." bundle:nil];
UIViewController controller = [storyboard instantiateInitialController];
[controller showWindow:sender];

How do I remove the "Start Dictation..." and "Emoji & Symbols" menu items under "Edit"?

NSMenu *editMenu = [[[[NSApplication sharedApplication] mainMenu] itemWithTag:EDIT_TAG] submenu];
for (NSMenuItem *item in [editMenu itemArray]) {
    if ([item action] == NSSelectorFromString(@"startDictation:") ||
        [item action] == NSSelectorFromString(@"orderFrontCharacterPalette:")) {
        [editMenu removeItem:item];
    }
}
// make sure a separator is not the bottom option
const NSInteger lastItemIndex = [editMenu numberOfItems] - 1;
if ([[editMenu itemAtIndex:lastItemIndex] isSeparatorItem]) {
    [editMenu removeItemAtIndex:lastItemIndex];
}

Copy and Paste

How do I handle the copy action?

- (IBAction)copy:(id)sender {
    NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
    [pasteboard declareTypes:@[ NSPasteboardTypePNG ] owner:nil];
    if ([pasteboard setData:pngData forType:NSPasteboardTypePNG]) {

How do I handle the paste action?

- (IBAction)paste:(id)sender {
    NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
    NSString *string = [pasteboard stringForType:NSPasteboardTypeString];

Keyboard Handling

How do I know if the Caps Lock key was pressed?

- (void)flagsChanged:(NSEvent*)event {
    if (event.keyCode == kVK_CapsLock) {

How do I know if the Control key was pressed?

- (void)keyDown:(NSEvent *)event {
    if (event.modifierFlags & NSEventModifierFlagControl) {

How do I get the "raw character" when the user pressed Option-character?

- (void)keyDown:(NSEvent *)event {
    event.charactersIgnoringModifiers

Mouse Handling

How do I track when the mouse enters or leaves a view?

self.trackingRectTag = [self addTrackingRect:self.bounds owner:self userData:NULL assumeInside:YES];
...
- (void)mouseEntered:(NSEvent *)event {
    ...
}

- (void)mouseExited:(NSEvent *)event {
    ...
}

How do I update the tracking rectangle if the view is resized?

[self removeTrackingRect:self.trackingRectTag];
self.trackingRectTag = [self addTrackingRect:self.bounds owner:self userData:NULL assumeInside:YES];

How do I handle mouse button clicks?

- (void)mouseDown:(NSEvent *)event;
- (void)mouseUp:(NSEvent *)event;
- (void)rightMouseDown:(NSEvent *)event;
- (void)rightMouseUp:(NSEvent *)event;

How do I handle mouse movement?

- (void)mouseMoved:(NSEvent *)event;
- (void)mouseDragged:(NSEvent *)event;  // needed for mouseMoved + mouseDown

Files and URLs

How do I know if a URL points a directory?

NSNumber *isDirectory;
([url getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:nil] && [isDirectory boolValue])

How do I know if a URL points to a package?

NSNumber *isPackage;
([url getResourceValue:&isPackage forKey:NSURLIsPackageKey error:nil] && [isPackage boolValue])

How do I enumerate the files in a directory?

NSURL *folder = ...;
NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager]
    enumeratorAtURL:folder
    includingPropertiesForKeys:nil
    options:(NSDirectoryEnumerationSkipsPackageDescendants | NSDirectoryEnumerationSkipsHiddenFiles)
    errorHandler:^(NSURL *url, NSError *error) { return YES; }];
for (NSURL *url in enumerator) {

How do I get the Desktop directory?

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDesktopDirectory, NSUserDomainMask, YES);

How do I create the Application Support directory?

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
NSString *bundleId = [[NSBundle mainBundle] bundleIdentifier];
NSString *supportDirectoryPath = [NSString stringWithFormat:@"%@/%@/", paths.firstObject, bundleId];
NSURL *url = [NSURL fileURLWithPath:supportDirectoryPath isDirectory:YES];

NSError *error;
[[NSFileManager defaultManager] createDirectoryAtURL:url withIntermediateDirectories:YES attributes:nil error:&error];

How do I replace the home directory in a path name with the "~" character?

Use NSString's stringByAbbreviatingWithTildeInPath

Tools

How do I regenerate .strings files for localization?

https://github.com/Flinesoft/BartyCrouch

How do I export one of the SF Symbols?

Find the symbol you want in the SF Symbols app and select it, then Edit > Copy Image As... to copy the SVG into the pasteboard. Paste into a text editor and save as a .svg file. It can then be used in HTML as

<img src="icon.svg" />

How do I tint the SVG to a specific color?

Use https://codepen.io/sosuke/pen/Pjoqqp to generate the filter and set it in CSS.

Clone this wiki locally