Páginas

Monday, August 30, 2010

Accessor Methods

Following my last post, I'm going to talk a little bit about the accessor methods in Objective-C.

Accessor methods, as you may know, are those methods used to get or set the value of an object's variable, without actually "seeing" it. As you might imagine these methods are used many times in most, if not all, object-oriented programming languages. Objective-C 2.0 provides a very elegant way to declare these methods and saving a lot of lines of code.

It uses the key words @property and @synthesize. In general, a declaration of a property looks like this:

@property (attributes) type name;

The attributes can include readwrite (default) or readonly (doesn't get a setter method). To describe how the setter works it can also include assign, retain or copy.
  • assign (default) - simple assignment, does not retain the new value. If it's an object type and you're not using the GC, don't use this.
  • retain - releases the old value and retains the new. With GC is the same as assign.
  • copy - makes a copy of the new value and assigns the variable to the copy. (often used for strings).
So, a property declaration in the header file should look something like this:


@interface ClassName : NSObject {
    int foo;
}
@property (readwrite,assign) int foo;
@end


And then, in the implementation file you just need to write @synthesize foo; and your accessor methods are defined.

NOTE: There are two ways of using these methods, the normal one is by sending a
message to the object:

[object setValue:newValue];

and there is the other way, that's called the dot syntax and is a lot like what you do in Java:

object.value = newValue;

Although you can use the dot syntax, I do not recommend it. Read this post for the reasons why.

Sunday, August 29, 2010

An Objective-C/Cocoa character counter program

I've been learning Objective-C and Cocoa since yesterday (yes, I'm a newbie, so don't judge... :P), but I'm really loving it.

For those who have no idea of what this is, Objective-C is a C object oriented extension and Cocoa is, according to the Wikipedia, one of Apple Inc.'s native object-oriented API's for the Mac OS X operating system. Both of them together provide a great way to create programs to Mac OS X.

I'm not going to try to explain Objective-C or Cocoa in detail, there are really good books for that (the idea for this example was taken from Cocoa® Programming for Mac® OS X (3rd Edition)), nor will I explain how to use Xcode as an IDE. I'll just write the code and a little explanation of what it does.

So, let's get to what really matters, the code! :D

Every class in Obj-C is composed by two files a header file (.h) and a source file (.m). The first one has the instance variables and methods declarations and the second one the actual code (remember that Objective-C is an extension of C).

Our header file will be something like this:

#import <Cocoa/Cocoa.h>

@interface Counter : NSObject {
    IBOutlet NSTextField *line;
    IBOutlet NSTextField *output;
}

-(IBAction)count:(id)sender;
@end


The first line imports the declaration of NSObject which Counter inherits from, similar to Java's Object. All the Objective-C keywords start with @, to minimize conflicts with C code, as @interface.

Both instance variables are of type pointer to NSTextField, that can be either a text field or a label. IBOutlet is a macro that evaluates to nothing, it's a hint to the Interface Builder.

Finally, there's the method declaration. The method has the name count, returns IBAction (the same as void, also a hint for the IB) and has one argument named sender and of type id (a pointer to any type of object).

The .m file will have to implement the declared method (Java's public methods), but other methods can be declared as well, new methods (Java's private methods) or override inherited methods. Ours will be like this:


#import "Counter.h"

@implementation Counter

-(void)awakeFromNib
{
    [output setStringValue:@"???"];
}
   
-(IBAction)count:(id)sender
{
    NSString *theLine = [line stringValue];
    int noChars = [theLine length];
    NSLog(@"Counted %d chars",noChars);
    [output setStringValue:[NSString stringWithFormat:@"'%@' has %d characters", theLine, noChars]];
}   

@end


The nib file is a collection of objects that have been archived. When the program is launched, the objects are brought back to life before the application handles any events from the user. After being brought to life but before any events are handled, all objects are automatically sent the message awakeFromNib. This means that the label will have the string value "???" when the program starts, it should look like the following picture:


In the Interface Builder you should connect the text field and label to the corresponding outlets and the action of the button to the count method. For this you will have to add an object of the class Counter to the Doc Window.


Now, you've made sure the count method will be called when the button is pressed. So, what does the count method do?

It's actually a pretty simple method, it gets the string the user has typed, by sending the stringValue message to the text field (this method is an accessor, the correspondent to Java's get). It then sends the length message to the string, to get the number of characters. We now have all the information we need.

After that it writes the character number to the console, and finally it sets the label's string.

The final result should be something like this:



In this code I assume that you have a version of Mac OS above 10.4 and that you have the garbage collector on. I'll cover the usage of retain counts, the alternative solution to the GC in the future.

Saturday, August 28, 2010

How to create a man page

OA very useful thing, as everyone that has ever used a shell knows, are the man pages. In this post I'll explain how to create a man page for your programs, from scratch.

First you have to create a file and write the actual text for the man page, using some special tags, the most important can be found here. This is the main step of the creation of the man page, and where you should spend most of the time.

So that you can check how your man page will look while you're writing it and/or after you've written it, there is a very useful program, nroff, that is used the following way:

nroff -e -mandoc yourFile | less -s

Once you feel your page is as you want it, you'll have to rename your file to XXX.1 (or any other number from 1 to 8, according to this standard) and then compress it using gzip or bzip2. Your man page is now ready!

If you try the command man yourFile, you'll notice it doesn't work. That's because you're man page isn't in the MANPATH yet. To do this you'll first have to move your file to a directory with the name manX, being X the number you chose from the 8 possible (it is normal to have a directory called man and all the manX directories to be it's children). So, let's do that:

mkdir path/to/program/man
mkdir path/to/program/man/man1
mv yourFile.1.gz path/to/program/man/man1


The last thing to be done is actually adding your man folder to the MANPATH, if it isn't already added. The first thing to do is check if you have to add it or not:

echo $MANPATH (Just to check if the folder is in the current MANPATH)
export MANPATH=path/to/program/man:$MANPATH


Instead of doing this, if you have root privileges, you can create a directory in one of the directories already pointed by the MANPATH, like /usr/share/man.

And that's it! Go try it out!

Thursday, August 26, 2010

Writing to NTFS with Mac OS

I recently had the need to write to an NTFS formatted disk and found out that I only had read permissions. I could not have this, therefore, and after some Internet searching,  I found out how to do this. This "hack" is a really easy one, but really useful as well, nonetheless.

Native file handling capabilities of the Mac Os can be extended using Google's MacFUSE, as can be read at the project's home page. At the same page you can download the .dmg and install it.

You're halfway through. Now you just need the NTFS part, that can be downloaded here, install it, restart and you're good to go!

The Tuxera product needs a license after 15 days, if you find one that works just the same and is free, please tell me something.

*UPDATE*: See the comments for a free product.

Sunday, August 15, 2010

Bash 101 - I/O Redirection and Pipes

Bash scripting is a subject I'm really fond of, but before starting to write scripts one needs to understand how the bash commands work and how they can be connected. That's the purpose of this post, to provide some background before getting into the actual writing of scripts.

I/O Redirection


Many commands such as ls print their output on the display. We can change this using operators under the I/O redirection category, to redirect the output of those commands to files, devices and also to the input of other commands.

There are 3 file descriptors, stdin (standard input), stdout (standard output) and stderr (standard error). Basically you can use redirection in 7 different ways:
  1. stdout 2 file
  2. stderr 2 file
  3. stdout 2 stderr
  4. stderr 2 stdout
  5. stderr and stdout 2 file
  6. stderr and stdout 2 stdout
  7. stderr and stdout 2 stderr
This file descriptors are represented by the numbers 0 (stdin), 1 (stdout) and 2 (stderr).
To make this clearer, let's give examples for each of the redirections.
  1. ls -l > output.txt
  2. grep something * 2> errors.txt
  3. ls -l 1>&2
  4. grep something * 2>&1
  5. rm -f $(find / -name core) &> /dev/null (redirects both stdout and stderr to /dev/null that automatically deletes that information)

Other cases:

> filename - this truncates the file to zero length and if the file is not present has the same effect as touch

>> filename - this operator can be used as normal redirection to a file, but instead of writing from the start it appends to the end of that file

command < filename - accepts input from a file

3<> filename - open file for reading and writing and assigns file descriptor 3 to it

n <&- - closes file descriptor n (this is useful with pipes, because child processes inherit open file descriptors)


Another kind of redirection are the HERE documents that I've mentioned before. With those you can redirect a dynamic file to the input of a program that receives a normal file. An example of this can be seen in my earlier post.

Pipes


Very simply put, pipes let you use the output of a program as the input of another. To do this, a process is created for each command. That's why being careful with which file descriptors are open at the moment of creation (before sending the output as input) of each of those processes is important.

The basic functionality of pipes can be understood with a very simple example that has the same effect as ls -l *.sh:

ls -l  |  grep "\.sh$"

Here, the output of the program ls -l is sent to the grep program, which, in turn, will print lines which match the regex "\.txt$".