Category Archives: macOS Development

How to add a macOS target to your iOS App

To write cross-platform applications, it can be beneficial to have a single project with several target architectures. For example, we may want a macOS App inside a project that started out as iOS, and vice versa. Or we may want a different version of our app, perhaps a free one with less features, and an expensive one with more, based on the same code.

That’s where Xcode Targets come in. A Target is something that defines several build settings about an app so that when we press that popular button in Xcode, it knows what to do so we can see the built app in full colour. Trust me, there’s a lot going on under the hood – if you’ve ever tried to compile from the command line, you know how super helpful that button is. But I digress…

In this example I’ll show you how we can add a macOS Target to an iOS App’s Project. This will allow us to run and build either an iOS or a macOS version from common code.

Let’s begin. I’m using Xcode 8.3.3 for this by the way.

Adding the Target

In a standard Xcode Project for iOS, we already have a single target. Click on the blue project bar and select it from the list next to the File Inspector. It’s the one with the yellow icon:

Continue reading





How to read keyboard input in C

We can use the scanf() function to get user input in C. Here’s a quick implementation of scanf():

#include <stdio.h>

char input[100];
char *output = "Thank you for your message!";

int main(int argc, const char * argv[]) {
    
    // ask user for some input
    puts("Tell me something nice:");
    
    // grab input from keyboard via scanf()
    // don't use gets() for this, apparently it's totally evil
    scanf("%s", input);
    
    // say goodbye
    printf("%s\n\n", output);
    
    return 0;
}

scanf() will wait for the user to press Enter before giving its returned value back to our app. We must define a variable to hold its output. We can even define multiple variables, each of which will be populated with whatever is being typed in until Enter is pressed. Consider this:

 char input1[100], input2[100], input3[100];
 scanf("%s, %s, %s", input1, input2, input3);

Here we wait for three string items to be added (numbers entered will be interpreted as strings). To grab a numeric value from the keyboard, we cam use %d like so (d as in decimal, variable defined as int):

 int number;
 scanf("%d", &number);

Note the ampersand in front of our variable, without which scanf would populate a pointer. We can also mix and match keyboard input like this:

 char string[100];
 int number;
 scanf("%s, %d", string, &number);

Demo Project

You’ll find a quick demo project on GitHub, which also serves as a template on how to setup Xcode to open Terminal and allow for keyboard input when the project is run.





How to define a struct in C

Structures (or structs) in C are something like “mini-objects”: they are wrappers around multiple variables, much like the properties of an object. Since plan C doesn’t have objects, these are as close as it gets to them, and they can be quite helpful. Apple uses them extensively (think of a CGRect for example), and it’s easy to build our own.

Here’s how we can do that.

Creating a struct

We can define a struct like this:

    // define a struct
    struct cube {
        int length;
        int width;
        int height;
    };

Here we create a struct with the name of cube and define three variables inside it. They don’t have to be of the same type, you can mix and match int, float, char and all the rest of the merry gang. The variables of a struct are called members.

When defined, a struct can be seen as a template. To use it, we need to initialise a new instance of the struct and populate the member variables, like so:

    // initialilze our struct
    struct cube massiveCube;

    // and populate it with values
    massiveCube.length = 5;
    massiveCube.width = 5;
    massiveCube.height = 7;

Our instance of the struct is called massiveCube, and we can refer to its member variables by dot notation.

The whole setup can be done in one step too, like this:

    // or define and init
    struct oval {
        int width;
        int height;
    } bigOval;
    
    bigOval.height = 5;
    bigOval.width = 7;

Note here that we still need to populate the variables. Further structs from the same template can be created as shown above.

Typedef-ing a struct

If we don’t want to create new struct instances with “struct cube myCube”, we can write a type definition for a struct.

typedef struct cube MegaCube;

I’ve typedef’d previous cube structure as MegaCube. Of course we can choose any name we like here, something descriptive is always a good idea. Again, our friends at Apple to this quite frequently. Now we can create new instances simply by referring to them without the struct word and only use our own definition:

MegaCube rubiksCube;
rubiksCube.length = rubiksCube.height = rubiksCube.width = 3;

This makes our code more readable and is a way of making C code “our own”.





How to read Command Line Input on macOS

I was building a simple Command Line Tool app for macOS. One thing the app needed was user input, i.e. it should wait for the user to type something that I’d like to make use of in the app.

Turns out it’s a rather complicated affair, and I haven’t found a comprehensive starter guide on how to actually accomplish this.

I wanted to create a Command Line Tool app that was capable of accepting text input from the Terminal window, use it, and then write output back for the user to read.

But that wasn’t enough: I also had to tell Xcode to setup the app appropriately, otherwise the Terminal window wasn’t launched – which is of course necessary for a Common Line Tool.

In this article we’ll do just that: prepare Xcode to launch Terminal, wait for input, and print it out again. Here we go.

Continue reading





How to test if an NSArray or NSSet contains an object

There’s a handy method in the NSArray class that lets us check if an array contains a particular object or not. The containsObject method returns a BOOL for us to evaluate.

Consider this:

// create an array
NSArray *array = @[@"Apples", @"Pears" , @"Bananas"];

// check if Pears are in the array
if ([array containsObject:@"Pears"]) {
    NSLog(@"We have Pears.");
}

Likewise, we can check if our array does not contain a particular object by testing the opposite:

// check if Grapes are not in the array
if (![array containsObject:@"Grapes"]) {
    NSLog(@"But we don't have Grapes.");
}

Both the NSMutableArray and NSSet classes has the same method, so we can check for the (un-)presence of our objects in mutable arrays and sets the same way.





How to populate an NSTableView in code

Screen Shot 2014-05-04 at 11.22.52I’ve previously shown you how to populate an NSTableView using Bindings and an array controller. Today I’ll show you how to do it in code.

It’s relatively simple and very similar to powering a UITableView. The main difference is that in Cocoa we don’t have a controller object that comes bundled with our view, so we’ll have to create one manually (or use an existing class). Here are the steps:

  • add an NSTableView to your XIB file
  • create a controller class based on NSObject (I’ll call mine TableController)
  • drag an NSObject object into the XIB (that blue box)
  • associate it with your custom controller object (i.e. TableController)
  • set the data source and implement its methods

In this example I’m using the numbers 1-10 in two arrays: as numbers, and as written out values – so that two columns of the table view can be populated with different items.

#pragma mark - Custom Initialisers

- (NSArray *)numbers {
    
    if (!_numbers) {
        _numbers = @[@"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9", @"10"];
    }
    return _numbers;
}

- (NSArray *)numberCodes {
    
    if (!_numberCodes) {
        _numberCodes = @[@"One", @"Two", @"Three", @"Four", @"Five", @"Six", @"Seven", @"Eight", @"Nine", @"Ten"];
    }
    return _numberCodes;
}

Next we’ll implement the following two methods: the first for returning the number of rows, and the second for returning the relevant data in each row:

#pragma mark - Table View Data Source

- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
    
    // how many rows do we have here?
    return self.numbers.count;
}

- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
    
    // populate each row of our table view with data
    // display a different value depending on each column (as identified in XIB)
    
    if ([tableColumn.identifier isEqualToString:@"numbers"]) {
        
        // first colum (numbers)
        return [self.numbers objectAtIndex:row];
    
    } else {
        
        // second column (numberCodes)
        return [self.numberCodes objectAtIndex:row];
    }
}

Notice that in the second method we’re not referencing the columns with a number (like we do with rows). That’s because the user could reorder or remove columns. Instead we’re using the column identifier which you can set in IB.

Reacting to selections

If you want to react to user selections in your code you need to implement the NSTableViewDelegate Protocol and also connect your table view’s delegate to the above class. Then simply implement this method and you’re notified when a user clicks a row:

#pragma mark - Table View Delegate

- (void)tableViewSelectionDidChange:(NSNotification *)notification {
    
    NSTableView *tableView = notification.object;
    NSLog(@"User has selected row %ld", (long)tableView.selectedRow);
}

Unlike in iOS, we’re not directly passed the table view object – but we can grab it from the notification. Note that the log message will be off by one because the rows start at 0 rather than 1.

Watch the Screencast

Here’s a demo project with the above steps implemented: