Thursday, July 26, 2007

Saving data using NSDictionaries

Okay, I had a blog viewer inquire about this problem. They were wanting to save information about people in a single XML file but didn't know how to do it. 

If you want to save information about people, the easiest way to do that is by using nested dictionaries where a single root dictionary contains dictionaries with your data. 

When you store all your dictionaries in a root dictionary, you can just write the root dictionary to file and and you will get an XML file representation of you data. 

I have a demonstration app up on the server, you just can't find it from the first page. 

Here is the link to the dictionary example to demonstrate how you do this. 
maccoder.server.googlepages.com/DictionaryExample.zip
Make sure you build it in XCode first before you run it. The current built file doesn't reflect a change I made in code to keep it from locking up your computer. 

I hope this helps!
Happy coding! :-)

Monday, July 16, 2007

Authenticating Users in Objective-C

Okay, so here is another solution. Let say you are creating an application that makes changes to your computer. You only want administrators to have the right to use your application. How do you go about doing this you might ask... Well, it is actually really simple. Here is how you access the built in authentication framework in Mac OS X in Objective-C.

First, you need to import some libraries. In the header file, import the following files:
  • Security/Authorization.h
  • Security/AuthorizationTags.h
Make sure you use the angle brackets instead of quotations.

This will give you access to the built in authentication and some variables to use for basic authentication.

Second, you need to declare some variables, you need the following:
  • OSStatus
  • AuthorizationRef
  • AuthorizationItem
  • AuthorizationRights
  • AuthorizationFlags
This is how I declared them in the demo app on the demo server. 

OSStatus status;
AuthorizationRef authorizationRef;
AuthorizationItem right = {kAuthorizationRightExecute, 0, NULL, 0);
AuthorizationRights rightSet = { 1, &right };
AuthorizationFlags flags = kAuthorizationFlagExtendRights | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagDefaults;

Now, you have declared all the variables you will need. Notice that you don't have the '*' next to the variable name. This is because you are leaving the realm of Objective-C and going into C/C++ and Objective-C will try to create id variables for all the items with the '*'. This will cause the application to stop responding.

To check authorization, you need to do the two methods. 

First, call this method:

status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authorizationRef);

This calls the dialog to open if you aren't already authenticated. 
After this method call, call this

status = AuthorizationCopyRights(authorizationRef, &rightSet, kAuthorizationEmptyEnvironment, flags, NULL);

This will extract the actual authorization for the user entered and set it to the status variable.

Now, you do a check.

if (status == errAuthorizationSuccess){ 
//do something 
}

That's it! If the user is authenticated, then the method body will be executed, else, it is left alone. Now, in the demo app, I had problems getting the application to keep working after the user closed the dialog, or put in bad information. So, I just surrounded the code with a @try @catch block.

Happy coding! :-)

Saturday, July 14, 2007

Accessing bundled files in Objective-C : NSBundle class

Okay, this is something new that I learned to do recently.

Lets say you have an application that has users. You want to give users the ability to set a picture to represent their account. Well, it's easier if you just have a default picture at first and allow them to change it later. The question is, how will you access that default picture in the application bundle. 
There is a class designed especially to allow us to do this type of thing. It is called NSBundle. 

So, now, you have a user set up a new account, you now need to access that default picture within the application bundle. This is how you will utilize the NSBundle class. 
  • NSImage *defaultImage = [[NSImage alloc] initWithFile:[[NSBundle mainBundle] pathForResource:@"default_image" ofType:@"png"]];
That's all there really is to do to access a bundled file. This opens up the door to many possibilities really. You can include in data files, defaults (like an image, default settings, etc...) and not really let the user have access to it. It also makes it easy for you to distribute any necessary files, in a user friendly way, for your application to work. 

I'm going to play with this some more but I think you can also write to your bundled file (like if you have a bundled database file or something). I'll check it out over the next couple of days and post about my findings. 

Happy Coding! :-)

Back from break!

Hey everyone, I'm back from break now. I had a little time off from school so I went back to my home to visit family. I'm now working with the Mac Team at LANDesk so now, I'm learning even more about how Cocoa and Objective-C work in the real world. I'm still willing to help you all out with problems with Objective-C so saying that, if there is anything that is challenging that you are having problems with in Objective-C, just post a comment to this post and I'll respond back ASAP! 

Happy Coding! :-) (That's now my new saying!)

Tuesday, June 5, 2007

Pulling in RTF Information in Objective-C

Okay,

So, a view pointed out that you can't pull in an RTF file because it's in binary.

I did some playing around and found a class derived from a string class called NSAttributedString.

If you want to pull in RTF information, this string does it. I successfully used this to pull in every line from an RTF in the application I posted to the demo server. I still haven't fixed it yet. But hey, RTF's are a possibility! :-)

To get the string data, I just created a new NSAttributedString and called the following init method.
  • [[NSAttributedString alloc] initWithPath:@"location.rtf" documentAttributes:nil];
Then I called the string property and returned a standard string.

The rest I solved using the way I demonstrated before.

Happy Coding :-)

Sunday, June 3, 2007

Reading in individual lines from a file in Objective-C

Okay, I had someone comment on the blog saying that they can get in the string information, they just need to filter out each line. This can be done easily. I also have an application up on the demo server so you can download the source.

It took me a little bit to figure out what the key was to symbolize a new line but it turns out to be a simple \n. So, this is what you have to do:

Read in your text to an NSString object, like so:
  • NSString *info = [NSString stringWithContentsOfFile:@"FilePath.txt"];
Or like this:
  • NSString *info = [[NSString alloc] initWithContentsOfFile:@"FilePath.txt"];
Then you split the string into an array list by doing the following.
  • NSArray *arrayOfLines = [info componentsSeparatedByString:@"\n"];
Now, you will have an array of all the lines in the file. This might actually be one of the slowest means of doing things, since the file has to be read into memory, but it works. And if you have some settings that need to be loaded in through a file, this might just be your thing.

The only bug I had with this was reading in a rich text file. A standard text file works fine doing this method. I hope this helps out. :-)

Saturday, June 2, 2007

Interacting with the command line in Objective-C

Okay,

Before, I thought that you could interact with the command line only through Apple Script. I found a different way of doing it. If you have a script file for command line, you can access it and utilize it by using one of the following methods in Objective-C (Note, These are C functions)
  • int result = system("Your Command Here");
If you want to get the output from this call, you will have to pipe the output to a file and read it in using Objective-C. You can pipe the output like this:
  • int result = system("Your Command Here > File.txt");
I'm going to try and get a demo up for this to better understand this sometime this weekend.

The result contains from my understanding a 1 if it completed without error or a 0 if it had an error, I could be wrong. All I know is if you handle the result like this.
  • if (!result) {}
Your code will fall through to this method if it had an error.

Now, if you have a script that can run in the background, you can use the following C command
  • FILE *fileObject = popen("Your Command Here");
As shown above, this will return a FILE Object. This is a C object. This contains all the information being sent to and returned from the console, so if you need to get back information, you will have to use some C functions to print it out.