objective-c revisited
global and static variables
To make a variable global, you declare it outside of a particular function.
#include <stdio.h> #include <stdlib.h> //declare a global variable float lastTemperature;
a static variable is like a global variable in that it is declared outside of any function. However, a static variable is only accessible from the code in the file where it was declared.
//declare a static variable in main.c static float lastTemperature; //initialize to 50 degrees static float last = 50.0;
stylish pointer declaration
what do you think these are?
float* b, c;
Surprise! b is a pointer to a float, but c is just a float;
Putting the * directly next to the variable name makes this clearer.
float *b,*c;
when the caller wants two parts return?
#include <stdio.h> #include <math.h> int main(int argc, const char * argv[]) { double pi = 3.14; double integerPart; double fractionPart; // Pass the address of integerPart as an argument fractionPart = modf(pi, &integerPart); // Find the value stored in integerPart printf("integerPart = %.0f, fractionPart = %.2f\n", integerPart, fractionPart); return 0; }
Pass by reference
void cartesianToPolar(float x, float y, float *rPtr, float *thetaPtr)
That is, when the function is called, it will be passed values for x and y. It will also be supplied with locations where the values for radius and theta can be stored.
void cartesianToPolar(float x, float y, double *rPtr, double *thetaPtr) { // Store the radius in the supplied address *rPtr = sqrt(x * x + y * y); ... // Store theta in the supplied address *thetaPtr = theta; }
Avoid dereferencing NULL
Sometimes a function can supply many values by re ference, but you may only care about some of them. How do you avoid declaring these variables and passing thei r addresses when you’re not going to use them anyway? Typically, you pass NULL as an address to tell the function “I don’t need this particular value.”
This means that you should always check to make sure the pointers are non-NULL before you dereference them.
Struct
// Here is the declaration of the struct Person struct Person { float heightInMeters; int weightInKilos; }; //Most of the time, you use a structure declaration over and over again. So it’s common to create a typedef for the structure type. //A typedef defines an alias for a type declaration and allows us to use it more like the usual data types. // Here is the declaration of the type Person typedef struct { float heightInMeters; int weightInKilos; } Person; Person person;
Simple Heap usage
#include <stdio.h> #include <stdlib.h> typedef struct { float heightInMeters; int weightInKilos; } Person; float bodyMassIndex(Person *p) { return p->weightInKilos / (p->heightInMeters * p->heightInMeters); } int main(int argc, const char * argv[]) { // Allocate memory for one Person structure Person *x = (Person *)malloc(sizeof(Person)); // Fill in two members of the structure x->weightInKilos = 81; x->heightInMeters = 2.0; // Print out the BMI of the original Person float xBMI = bodyMassIndex(x); printf("x has a BMI of = %f\n", xBMI); // Let the memory be recycled free(x); // Forget where it was x = NULL; return 0; }
Foundation
Command Line Tool, Type:Foundation,
#import <Foundation/Foundation.h> int main (int argc, const char * argv[]) { @autoreleasepool { NSDate *now = [NSDate date]; NSLog(@"The new date lives at %p", now); NSLog(@"The new date lives at %@", now); } return 0; }
%p prints out the location of the object.
%@ prints out the description of the object.
Instance variable to properties
#import <Foundation/Foundation.h> // The class Person inherits all the instance variables // and methods defined by the class NSObject @interface Person : NSObject { // It has two instance variables float heightInMeters; int weightInKilos; } // You will be able to set those instance variables using these methods - (void)setHeightInMeters:(float)h; - (void)setWeightInKilos:(int)w; // This method calculates the Body Mass Index - (float)bodyMassIndex; @end
Apple has created a handy way to simplify writing accessor methods called properties. With a property, you can declare both the setter and getter methods in one line.
#import <Foundation/Foundation.h> @interface Person : NSObject { float heightInMeters; int weightInKilos; } @property float heightInMeters; @property int weightInKilos; - (float)bodyMassIndex; @end
#import "Person.h" @implementation Person @synthesize heightInMeters, weightInKilos; - (float)bodyMassIndex { return weightInKilos / (heightInMeters * heightInMeters); } @end
Retain cycle
In a parent-child relationship, the general rule for preventing this type of retain cycle is the parent owns the child, but the child should not own the parent.
What if you want a collection of floats or int s or pointers to structures? You can wrap co mmon C primitive types in an object. There are
two classes that are designed sp ecifically for this purpose. NSNumber holds C number types. NSValuecan hold a pointer and some types of structs. You are not allowed to add nil to any of the collection classes we have covered. What if you need to put that idea of nothingness, a “hole, ” into a collection? There is a class called NSNull .
What is the difference between #include and #import? #import ensures that the preprocessor only includes a file once. #include will allow you to include the same file many times. C programmers tend to use #include . Objective-C programmers tend to use #import.
In a project, it used to be pretty common to include a collection of headers in every file of code. This led to clutter at the beginning of your file and made compiles take longer. To make life easier and compiles faster, most Xcode projects have a file that lists headers to be precompiled and
included in every file. In your project, this file is called XXX-Prefix.pch .
Constant
#import <Foundation/Foundation.h> int main (int argc, const char * argv[]) { @autoreleasepool { NSLog(@"\u03c0 is %f", M_PI); NSLog(@"%d is larger", MAX(10, 12)); NSLocale *here = [NSLocale currentLocale]; NSString *currency = [here objectForKey: NSLocaleCurrencyCode ]; NSLog(@"Money is %@", currency); } return 0; }
When the class NSLocale was written, this global variable appeared in two places. In NSLocale.h , the variable was declared something like this:
extern NSString const *NSLocaleCurrencyCode;
The const means that this pointer will not change for the entire life of the program. The extern means “I promise this exists, but it will be defined in some other file.” And sure enough, in the file NSLocale.m , there is a line like this:
NSString const *NSLocaleCurrencyCode = @"currency";