19 Mart 2010 Cuma

Allocation

Allocation is the process by which a new object is born. It’s the happy time
when a chunk of memory is obtained from the operating system and desig-
nated as the location that will hold the object’s instance variables. Sending
the alloc message to a class causes that class to allocate a chunk of memory
large enough to hold all its instance variables. alloc also conveniently initial-
izes all the memory to 0. That way, you don’t have the problem of uninitialized
memory causing all sorts of random bugs that afflicts many languages. All
your BOOLs start out as NO; all your ints are 0; all your floats become 0.0; all
your pointers are nil;

string = [[NSString alloc]
initWithContentsOfFile: @"/tmp/words.txt"];

objective-C

That Wacky #import Thing
Just like C, Objective- C uses header files to hold the declarations of elements such as
structs, symbolic constants, and function prototypes. In C, you use the #include statement
to inform the compiler that it should consult a header file for some definitions. You can
use #include in Objective- C programs for the same purpose, but you probably never will.
Instead, you’ll use #import, like this:
#import
#import is a feature provided by the GCC compiler, which is what Xcode uses when you’re
compiling Objective- C, C, and C++ programs. #import guarantees that a header file will be
included only once, no matter how many times the #import directive is actually seen for
that file.

NSLog()

#import  
int main (int argc, const char * argv[])
{
const char *words[4]
= { "Joe- Bob \"Handyman\" Brown",
"Jacksonville \"Sly\" Murphy",
"Shinara Bain",
"George \"Guitar\" Books" };
int wordCount = 4;
int i;
for (i = 0; i < wordCount; i++) {
NSLog (@"%s is %d characters long",
words[i], strlen(words[i]));
}
return (0);
} // main


Joe-Bob "Handyman" Brown is 24 characters long
Jacksonville "Sly" Murphy is 25 characters long
Shinara Bain is 12 characters long
George "Guitar" Books is 21 characters long

#import  
int main (int argc, const char * argv[])
{
FILE *wordFile = fopen ("/tmp/words.txt", "r");
char word[100];
while (fgets(word, 100, wordFile)) {
// strip off the trailing \n
word[strlen(word) - 1] = ‘\0’;
NSLog (@"%s is %d characters long",
word, strlen(word));
}
fclose (wordFile);
return (0);
} // main



typedef enum { 
kCircle,
kRectangle,
kOblateSpheroid
} ShapeType;

typedef struct {
ShapeType type;
ShapeColor fillColor;
ShapeRect bounds;
} Shape;

typedef struct {
int x, y, width, height;
} ShapeRect;

ShapeRect rect0 = { 0, 0, 10, 30 };





int main (int argc, const char * argv[]) 
{
id shapes[3];
ShapeRect rect0 = { 0, 0, 10, 30 };
shapes[0] = [Circle new];
[shapes[0] setBounds: rect0];
[shapes[0] setFillColor: kRedColor];
ShapeRect rect1 = { 30, 40, 50, 60 };
shapes[1] = [Rectangle new];
[shapes[1] setBounds: rect1];
[shapes[1] setFillColor: kGreenColor];
ShapeRect rect2 = { 15, 19, 37, 29 };
shapes[2] = [OblateSphereoid new];
[shapes[2] setBounds: rect2];
[shapes[2] setFillColor: kBlueColor];
drawShapes (shapes, 3);
return (0);
} // main


standard definition

@interface Shape : NSObject 
{
ShapeColor fillColor;
ShapeRect bounds;
}
- (void) setFillColor: (ShapeColor) fillColor;
- (void) setBounds: (ShapeRect) bounds;
- (void) draw;
@end // Shape



In Objective- C, you compose by including pointers to objects as instance
variables. So, our virtual unicycle would have a pointer to a Pedal object and
a pointer to a Tire object and would look something like this:
@interface Car : NSObject 
{
Engine *engine;
Tire *tires[4];
}
- (void) print;
@end // Car

@implementation Car
- (id) init
{
if (self = [super init]) {
engine = [Engine new];
tires[0] = [Tire new];
tires[1] = [Tire new];
tires[2] = [Tire new];
tires[3] = [Tire new];
}
return (self);
} // init




This line of code in the init method looks a little odd:
if (self = [super init]) { 
We’ll explain what’s happening here. You need to call [super init] so that the superclass (NSObject, in this case) can do any one- time initialization that it needs to do. The init method returns a value (of type id, a generic object pointer) representing the object that was initialized.
Assigning the result of [super init] back to self is a standard Objective- C convention. We do this in case the superclass, as part of its initialization work, returns a different object than the one originally created. We’ll explore this in depth in a later chapter when we cover init methods in more detail, so for now, please just nod and smile over this line of code, and we’ll move on.

Accessor Methods

@interface Car : NSObject 
{
Engine *engine;
Tire *tires[4];
}
- (Engine *) engine;
- (void) setEngine: (Engine *) newEngine;
- (Tire *) tireAtIndex: (int) index;
- (void) setTire: (Tire *) tire
atIndex: (int) index;
- (void) print;
@end // Car


@class sets up a forward reference. This is a way to tell the compiler, “Trust me; you’ll learn eventually
what this class is, but for now, this is all you need to know.”
@class is also useful if you have a circular dependency. That is, class A uses class B, and class B uses
class A. If you try having each class #import the other, you’ll end up with compilation errors. But if you
use @class B in A.h and @class A in B.h, the two classes can refer to each other happily.

hanging the Company Name

//
// TapDance.h
// Groovilicous
//
// Created by markd on 7/25/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//


defaults write com.apple.Xcode PBXCustomTemplateMacroDefinitions➥
'{"ORGANIZATIONNAME" = "Length-O- Words.com";}'



NSRange range;
range.location = 17;
range.length = 4;

NSRange range = { 17, 4 };


NSString
unsigned int length = [height length];
or in expressions like so:
if ([height length] > 35) {
NSLog (@"wow, you're really tall!");
}

NSString *thing1 = @"hello 5";
NSString *thing2;
thing2 = [NSString stringWithFormat: @"hello %d", 5];

if ([thing1 isEqualToString: thing2]) {
NSLog (@"The strings are the same!");
}
is different from
if (thing1 == thing2) {
NSLog (@"They are the same object!");
}
Similarly, [@"zoinks" compare: @"jinkies"] would return NSOrderedDescending. And,
as you’d expect, [@"fnord" compare: @"fnord"] would return NSOrderedSame.

if ([thing1 compare: thing2
options: NSCaseInsensitiveSearch
| NSNumericSearch]
== NSOrderedSame) {
NSLog (@"They match!");
}

if ([fileName hasSuffix: @".mov") {
// this is a movie
}

To split an NSArray, use -componentsSeparatedByString:, like this:
NSString *string = @"oop:ack:bork:greeble:ponies"; 
NSArray *chunks = [string componentsSeparatedByString: @":"];

And to join an NSArray and create a string of its contents, use componentsJoinedByString::
string = [chunks componentsJoinedByString: @"  :- ) "]; 

The preceding line would produce an NSString with the contents “oop :- ) ack :- ) bork :- ) greeble :- ) ponies”.


Mutability

Programmers coming from Java should feel at home with this distinction. NSString behaves like the
java String class, and NSMutableString is like Java’s StringBuffer class.


NSMutableString *string;
string = [NSMutableString stringWithCapacity: 50];
[string appendString: @"Hello there "];
[string appendFormat: @"human %d!", 39];

NSArray

NSArray *array; 
array = [NSArray arrayWithObjects:
@"one", @"two", @"three", nil];

int i;
for (i = 0; i < [array count]; i++) {
NSLog (@"index %d has %@.",
i, [array objectAtIndex: i]);
}


NSMutableArray *array; 
array = [NSMutableArray arrayWithCapacity: 17];

Add objects to the end of the array by using addObject:.
- (void) addObject: (id) anObject;
You can add four tires to an array with a loop like this:
for (i = 0; i < 4; i++) { 
Tire *tire = [Tire new];
[array addObject: tire];
}

[array removeObjectAtIndex: 1];



Enumeration

NSEnumerator *enumerator; 
enumerator = [array objectEnumerator];
id thingie;
while (thingie = [enumerator nextObject]) {
NSLog (@"I found %@", thingie);
}

Tire *t1 = [Tire new];
Tire *t2 = [Tire new];
Tire *t3 = [Tire new];
Tire *t4 = [Tire new];


NSDictionary *tires;
tires = [NSDictionary dictionaryWithObjectsAndKeys:
t1, @"front- left", t2, @"front- right",
t3, @"back- left", t4, @"back- right", nil];

Tire *tire = [tires objectForKey: @"back- right"];

NSMutableDictionary *tires;
tires = [NSMutableDictionary dictionary];
[tires setObject: t1 forKey: @"front- left"];
[tires setObject: t2 forKey: @"front- right"];
[tires setObject: t3 forKey: @"back- left"];
[tires setObject: t4 forKey: @"back- right"];



NSValue, NSNull
NSNumber is actually a subclass of NSValue, which wraps arbitrary values. You can use
NSValue to put structures into NSArrays and NSDictionaries. Create a new NSValue using
this class method:

NSValue *value; 
value = [NSValue valueWithBytes: &rect
objCType: @encode(NSRect)];
[array addObject: value];

[contact setObject: [NSNull null]
forKey: @"home fax machine"];

id homefax;
homefax = [contact objectForKey: @"home fax machine"];
if (homefax == [NSNull null]) {
// ... no fax machine. rats.
}




NSFileManager


NSFileManager *manager;
manager = [NSFileManager defaultManager];
NSString *home;
home = [@"~" stringByExpandingTildeInPath];
NSDirectoryEnumerator *direnum;
direnum = [manager enumeratorAtPath: home];
NSMutableArray *files;
files = [NSMutableArray arrayWithCapacity: 42];
NSString *filename;
while (filename = [direnum nextObject]) {
if ([[filename pathExtension]
isEqualTo: @"jpg"]) {
[files addObject: filename];
}
}
NSEnumerator *fileenum;
fileenum = [files objectEnumerator];
while (filename = [fileenum nextObject]) {
NSLog (@"%@", filename);
}