Mutable / Unmutable basic Data Type

Cooca prevede tue tipologie di contenitori, unmutable più efficienti ma non si possono modificare dopo la loro creazione, mutable per tutti gli altri casi.

NSArray -> NSMutableArray  :: gruppo ordinato accessibile per indice di elementi dello stesso tipo
NSDictionary -> NSMutableDictionary :: gruppo di elementi per accessibile nome
NSSet -> NSMutableSet :: gruppo di elementi, utile a rispondere alla domanda, il valore $x è contenuto in $set?
NSData :: array di byte rappresentante dati binari

siccome le mutabli discendono dalle immutabili, si possono usare indifferentemente

NSMutableArray *foo = SomeFunctionReturningAnNSMutableArray();
NSArray * bar = foo;// conversione implicita

oppure ottenere una copia immutabile

NSMutableArray *foo = SomeFunctionReturningAnNSMutableArray();
NSArray * bar = [foo copy];

modificare

NSMutableDictionary *dict;
 
dict = [NSMutableDictionary new];
AUTORELEASE (dict);
[dict setObject: @"/opt/picture.png"
         forKey: @"Luca"];
[dict setObject: @"/home/nico/birthday.png"
         forKey: @"Birthday Photo"];
[dict setObject: @"/home/nico/birthday.png"
         forKey: @"Birthday Image"];
[dict setObject: @"/home/marghe/pic.jpg"
         forKey: @"My Sister"];
To remove a key and its associated value, you can just use the method -removeObjectForKey::
 
[dict removeObjectforKey: @"Luca"];

iterare

array:

for( int i=0; i<[foo count]-1; i++){}

dictionary:

dict = [NSDictionary dictionaryWithObjectsAndKeys:
               @"/opt/picture.png", @"Luca",
               @"/home/nico/birthday.png", @"Birthday Photo",
               @"/home/nico/birthday.png", @"Birthday Image",
               @"/home/marghe/pic.jpg", @"My Sister", nil];
NSEnumerator * e = [dict keyEnumerator];
id obj;
while (obj = [e nextObject]) {
  // [e objectForKey]
  NSLog(@"Key: %@", obj);
}

set: NSSet also provides an enumerator over its contained objects via its objectEnumerator method.

Blocchi di codice anonimi possono essere usati per iterare collezioni

Stringhe

NSString è immutable, NSMutableString mutabile

{int,float,double}Value - intValue, floatValue, and doubleValue: convertono da str aun tipo specifico stringByAppendingString, stringByAppendingFormat:

NSString * s = @"Foo";
NSLog("%@\n", [s stringByAppendingFormat:@"3=%d",3]);

stringWithCString, cString : restituiscono NULL-terminated string.

const char *foo = "Blah blah";
NSString *bar;
// Create an NSString from a C string
bar = [NSString stringWithUTF8String:foo];
// Create a C string from an NSString
foo = [bar UTF8String];
NSString *name = @"Nicola";
NSMutableString *str;
str = [NSMutableString stringWithFormat: @"Hello, %@", name];
 
string = [[NSString alloc]
initWithFormat: @"%d or %d", 25, 624];
 
 
string = [[NSString alloc]
initWithContentsOfFile: @"/tmp/words.txt"];

Strings without NSString

C also has a mechanism for dealing with strings, but because C is not an object oriented programming language it does not have any of the advantages offered to us through the NSString class. For example, to use the C approach to creating strings we have to set up a pointer to a string of characters:

char *myString = "This is a C character string";
// C style character array to contain a string:
char myString[] = "This is a C character array";

A constant string object is declared by encapsulating the string in double quotes (") preceded by an @ sign. For example:

@"This is a constant character string object";

In order to display the current value of a string object using NSLog, simply reference the string using '%@' as follows:

NSLog (@"%@", @"This is a constant character string object");

Even though all we are doing here is creating a constant string object, keep in mind that this is still an object. As such, it has a range of methods that we can call on it. For example string objects have a length method that returns the number of characters in the string. We can, therefore, call this on a constant string object:

int len = [@"Hello" length];
NSLog (@"Length of string = %i", len);

The above code declares a constant string object containing the word "Hello" and calls the length method of object. The result is assigned to an integer variable named len which in turn is displayed using NSLog. When compiled and executed, we get the following output: Length of string = 5 Constant string objects are actually instantiated from the NSConstantString class which, much like the other classes we will look at in this chapter, is actually a subclass of the NSString class. In practice, given the way that constant strings are used, it is unlikely that you will need to specifically declare your string constants as being of type NSConstantString. It is more likely that you will declare the string as we have done in this section and let the compiler handle the rest.

Creating Mutable and Immutable String Objects

Two additional types of Objective-C string objects are mutable and immutable. When you create a string object of type NSString you are creating an immutable string object. This means that once a string has been assigned to the object, that string cannot subsequently be modified in any way.

NSString *string1 = @"This string is immutable";

Mutable string objects, are declared using the NSMutableString. NSMutableString is a subclass of NSString, which in turn is a subclass of NSObject. Instead, the string constant must be copied into the mutable string object. For example:

NSMutableString *string2 = [NSMutableString stringWithString:@"This string is mutable"];

Once a string has been declared as immutable, the only way to get a mutable version of the string is to create a mutable string object and copy the contents of the immutable string object to it. This can be achieved using the NSMutableString stringWithString class method.

NSString *string1 = @"This is a string";
NSMutableString *string2;
string2 = [NSMutableString stringWithString: string1];

Getting the Length of a String

NSString *string1 = @"This string is Immutable";
int len = [string1 length];
NSLog (@"String length is %i", len);
NSMutableString *string1;
NSMutableString *string2;
string1 = [NSMutableString stringWithString: @"This is a string"];
string2 = string1;

What we have achieved here is to create two variables (string1 and string2) that point to the memory location of the same string object. This is because the '*' before the variable names in the declarations indicates that this is a pointer to an object, not an actual object. Any time that we access the object referenced by either of these pointers we will, in fact, be accessing the same object. To prove this, we can make a change using the string2 reference and then display the string associated with both the string1 and string1 object pointers:

NSMutableString *string1;
NSMutableString *string2;
string1 = [NSMutableString stringWithString: @"This is a string"];
string2 = string1;
[string2 appendString: @" and it is mine!"];
NSLog (@"string1 = %@", string1);
NSLog (@"string2 = %@", string2);

To actually copy one string object to another string object we must use stringWithString method the NSMutableString class:

NSMutableString *string1;
NSMutableString *string2;
string1 = [NSMutableString stringWithString: @"This is a string"]; // Initialize string1
string2 = [NSMutableString stringWithString: string1]; // Copy string1 object to string2
[string2 appendString: @" and it is mine!"]; // Modify string2
NSLog (@"string1 = %@", string1);
NSLog (@"string2 = %@", string2);

When executed, the appended text appears only in the object referenced by string2 since string2 now references a different object to that referenced by string1:

2009-11-03 14:42:10.426 t[32263:10b] string1 = This is a string
2009-11-03 14:42:10.427 t[32263:10b] string2 = This is a string and it is mine!

Searching for a Substring

A common requirement when working with strings is to identify whether a particular sequence of characters appears within a string. This can be achieved using the rangeOfString method. This method returns a structure of type NSRange. The NSRange structure contains a location value providing the index into the string of the matched substring and a length value indicating the length of the match.

NSString *string1 = @"The quick brown fox jumped";
NSRange match;
match = [string1 rangeOfString: @"brown fox"];
NSLog (@"match found at index %i", match.location);
NSLog (@"match length = %i", match.length);

In the event that no match is found, the rangeOfString method will set the location member of the NSRange structure to NSNotFound.

NSString *string1 = @"The quick brown fox jumped";
NSRange match;
match = [string1 rangeOfString: @"brown dog"];
if (match.location == NSNotFound)
    NSLog (@"Match not found");
else
    NSLog (@"match found at index %i", match.location);

Replacing Parts of a String

Sections of a mutable string may be replaced by other character sequences using the replaceCharactersInRange method,only works on mutable string objects. The first argument is an NSRange structure consisting of the location of the first character and the total number of characters to be replaced. The second argument is the replacement string. An NSRange structure can be created by calling NSMakeRange and passing though the location and length values as arguments. For example, to replace the word "fox" with "squirrel" in our sample mutable string object we would write the following code:

NSMutableString *string1 = [NSMutableString stringWithString: @"The quick brown fox jumped"];
[string1 replaceCharactersInRange: NSMakeRange(16, 3) withString: @"squirrel"];
NSLog (@"string1 = %@", string1);

As you may have noted from the above example, the replacement string does not have to be the same length as the range being replaced.

String Search and Replace use rangeOfString to provide us with an NSRange structure for the substring to be replace and then pass this through to replaceCharactersInRange to perform the replacement:

NSMutableString *string1 = [NSMutableString stringWithString: @"The quick brown fox jumped"];
 
[string1 replaceCharactersInRange: [string1 rangeOfString: @"brown fox"] withString: @"black dog"];

Deleting Sections of a String

NSMutableString *string1 = [NSMutableString stringWithString: @"The quick brown fox jumped"];
[string1 deleteCharactersInRange: [string1 rangeOfString: @"jumped"]];

Extracting a Subsection of a String

NSMutableString *string1 = [NSMutableString stringWithString: @"The quick brown fox jumped"];
NSString *string2;
string2 = [string1 substringWithRange: NSMakeRange (4, 5)];
NSLog (@"string2 = %@", string2);
NSMutableString *string1 = [NSMutableString stringWithString: @"The quick brown fox jumped"];
NSString *string2;
string2 = [string1 substringFromIndex: 4];

Inserting Text into a String

NSMutableString *string1 = [NSMutableString stringWithString: @"The quick brown fox jumped"];
[string1 insertString: @"agile, " atIndex: 4];

Appending Text to the End of a String

NSMutableString *string1 = [NSMutableString stringWithString: @"The quick brown fox jumped"];
[string1 appendString: @" over the lazy dog"];
NSLog (@"string1 = %@", string1);

Comparing Strings attenzione a non comparare posizioni di memoria con == operator

NSString *string1 = @"My String";
NSString *string2 = @"My String 2";
 
if ([string1 isEqualToString: string2])
        NSLog (@"Strings match");
else
        NSLog (@"Strings do not match");

Checking for String Prefixes and Suffixes

NSString *string1 = @"The quick brown fox jumped";
BOOL result;
result = [string1 hasPrefix: @"The"];
if (result)
        NSLog (@"String begins with The");
result = [string1 hasSuffix: @"dog"];
if (result)
        NSLog (@"String ends with dog");

Converting to Upper or Lower Case

capitalizedString and lowercaseString

NSString *string1 = @"The quicK brOwn fox jumpeD";
NSString *string2;
 
string2 = [string1 capitalizedString];
string2 = [string1 lowercaseString];
string2 = [string1 uppercaseString];

Converting Strings to Numbers

Convert String to int
NSString *string1 = @"10";
 
int myInt = [string1 intValue];
 
NSLog (@"%i", myInt);
Convert String to double
NSString *string1 = @"10.1092";
 
double myDouble = [string1 doubleValue];
 
NSLog (@"%f", myDouble);
Convert String to float
NSString *string1 = @"10.1092";
 
float myFloat = [string1 floatValue];
 
NSLog (@"%f", myFloat);
Convert String to NSInteger
NSString *string1 = @"10";
 
NSInteger myInteger = [string1 integerValue];
 
NSLog (@"%li", myInteger);

Converting a String Object to ASCII

NSString *string1 = @"The quick browen fox";
 
const char *utfString = [string1 UTF8String];
 
printf ("Converted string = %s\n", utfString);

Error handling / Eccezioni

Exceptions are resource-intensive in Objective-C. You should not use exceptions for general flow-control, or simply to signify errors. Instead you should use the return value of a method or function to indicate that an error has occurred, and provide information about the problem in an error object.

 
// creare e lanciare eccezioni
NSException *exception = [NSException exceptionWithName:@"HotTeaException"
                            reason:@"The tea is too hot"  userInfo:nil];
@throw exception;
 
// catturare e gestire
@try {
    ...
} @catch (CustomException *ce) {
    ...
} @catch (NSException *ne) {
    ...
} @catch (id ue) {
    ...
} @finally {
    // Perform processing necessary whether an exception occurred  or not.
}

assertion:

NSAssert1((0 <= component) && (component <= 255),
        @"Value %i out of range!", component);

Memory

- (id)initWithFrame:(NSRect)rect {
    if (![super initWithFrame:rect])
    return nil;
    NSLog(@"initializing view");
    bgColor = [[NSColor yellowColor] retain];
    string = @" ";
    return self;
}
- (void)dealloc {
    [bgColor release];
    [string release];
    [super dealloc];
}

Take a look at NSObject.h for ASSIGN(), RELEASE(), RETAIN(), etc.

The most common way to handle release/retain is this:

@interface MyObject: NSObject {
  id myData;
}
-(void) setMyData: (id) newData;
-(id) myData;
@end
 
@implementation MyObject
- (void) setMyData: (id) newData {
  ASSIGN(myData, newData);
}
 
- (id) myData {
  return myData;
}
 
- (void) dealloc {
  RELEASE(myData);
}
@end

Basically it works for me. ASSIGNCOPY() can also be used to copy object. Always use

[self setMyData: newData]

to set myData, or at least use ASSIGN(myData, newData). Don't use myData = newData. By this way, you don't need to worry about the memory management.

In some case, I will use mutable classes because they are thread-safe. For example:

@interface MyObject: NSObject
{
  NSMutableArray *myArray;
}
-(void) setMyArray: (NSArray *) newArray;
-(NSArray *) myArray;
@end
 
@implementation MyObject
- (id) init
{
  myArray = [NSMutableArray new];
}
 
- (void) setMyArray: (NSArray *) newArray
{
  [myArray setArray: newArray];
}
 
- (NSArray *) myArray
{
  return myArray;
}
 
- (void) dealloc
{
  RELEASE(myArray);
}
@end

Mutable classes cost more resources. But it is a lazy way to avoid problems.

Also be aware of the return values from GNUstep classes. Some are autoreleased. For example,

[NSArray arrayWith...],
// or
[@"A string" stringBy...]

If you release them again, the application usually crashes. And remember to retain them if you want to use them later, and release them in -dealloc. It's safe to use ASSIGN() in this case.

ASSIGN(myString, [@"A string", stringBy...])
ASSIGN() // will handle all the details.

Again, once you use ASSIGN(), release it in -dealloc.

OOP

@protocol -> java interface @interface -> java class

defining Classes

@class Rectangle, Circle; This directive simply informs the compiler that "Rectangle" and "Circle" are class names. It doesn't import their interface files.

The @class directive minimizes the amount of code seen by the compiler and linker, and is therefore the simplest way to give a forward declaration of a class name. Being simple, it avoids potential problems that may come with importing files that import still other files. For example, if one class declares a statically typed instance variable of another class, and their two interface files import each other, neither class may compile correctly.

  1. Only #import the super class in header files.
  2. import all classes you send messages to in implementation.
  3. Forward declarations for everything else.

istanziare una classe:

[SomeClass new] ma [[SomeClass alloc] init]

ma common Cocoa convention is to use alloc and init.

- (id) init {
    if (self = [super init]) { // ricorda di eseguire il costruttore delle genittrici
      // codice di inizializzazione del'oggetto
    }
    return (self); // occorre ritornare
}

dynamic class programming

#import "FirstClass.m"
#import "SecondClass.m"
#import <stdio.h>
int main() {
    FirstClass *fClassObj = [[FirstClass alloc] init];
    SecondClass *sClassObj = [[SecondClass alloc] init];
    /* some methods to work with dynamic types */
    // -(BOOL) isKindOfClass: classObj  ----------- true
     if ( [fClassObj isKindOfClass: [FirstClass class]] == YES ) {
        printf( "fClassObj is kind of FirstClass.\n" );
    }
 
    // -(BOOL) isKindOfClass: classObj  ----------- false
    if ( [fClassObj isKindOfClass: [SecondClass class]] == YES ) {
        printf( "fClassObj is kind of SecondClass.\n" );
    }
    else
    printf( "fClassObj is not kind of SecondClass.\n" );
    // -(BOOL) isMemberOfClass: classObj ----------- true
     if ( [fClassObj isMemberOfClass: [FirstClass class]] == YES ) {
        printf( "fClassObj is member of FirstClass.\n" );
    }
    // -(BOOL) isMemberOfClass: classObj ----------- false
     if ( [sClassObj isMemberOfClass: [FirstClass class]] == YES ) {
        printf( "sClassObj is member of FirstClass.\n" );
    }
    else
    printf( "sClassObj is not member of FirstClass.\n" );
    // -(BOOL) respondsToSelector: selector ----- true
    if ( [fClassObj respondsToSelector: @selector(fShow)] == YES ) {
        printf( "fClassObj responds to fShow method\n" );
    }
    // -(BOOL) respondsToSelector: selector ----- false
    if ( [sClassObj respondsToSelector: @selector(fShow)] == YES ) {
        printf( "sClassObj responds to fShow method\n" );
    }
    else
       printf( "sClassObj does'nt respond to fShow method\n" );
    // release memory allocated for the objects
    [fClassObj release];
    [sClassObj release];
    return 0;
}

Introspection

while ( id anObject = [objectEnumerator nextObject] ) {
    if ( [self class] == [anObject superclass] ) {
        // do something appropriate...
    }
}
 
if ([item isKindOfClass:[NSData class]]) {
    const unsigned char *bytes = [item bytes];
    unsigned int length = [item length];
    // controllando che item sia una sottoclasse di NSData ci si assicura che rispetti la sua interfaccia
}
 
// whether an object implements a certain method
- (void)doCommandBySelector:(SEL)aSelector {
    if ([self respondsToSelector:aSelector]) {
        [self performSelector:aSelector withObject:nil];
    } else {
        [_client doCommandBySelector:aSelector];
    }
}
 
 
// conformsToProtocol, protocol, if necessary, and implements all the methods of the protocol
if (!([((id)testObject) conformsToProtocol:@protocol(NSMenuItem)])) {
    NSLog(@"Custom MenuItem, '%@', not loaded; it must conform to the
        'NSMenuItem' protocol.\n", [testObject class]);
    [testObject release];
    testObject = nil;
}

vedi anche isMemberOfClass:

Patterns

Singleton

static MyGizmoClass *sharedGizmoManager = nil;
 
+ (MyGizmoClass*)sharedManager {
    if (sharedGizmoManager == nil) {
        sharedGizmoManager = [[super allocWithZone:NULL] init];
    }
    return sharedGizmoManager;
}
+ (id)allocWithZone:(NSZone *)zone {
    return [[self sharedManager] retain];
}
- (id)copyWithZone:(NSZone *)zone {
    return self;
}
- (id)retain {
    return self;
}
- (NSUInteger)retainCount {
    return NSUIntegerMax;  //denotes an object that cannot be released
}
- (void)release {
    //do nothing
}
- (id)autorelease {
    return self;
}

GCC

How can I link a C++ library into an Objective-C program ?

c++ -c file.m
c++ file.o -lcpluslib -o myprogram

How do I compile .m files with the GNU C compiler ?

gcc -c class.m
gcc -o class class.o -lobjc -lpthread