In this lesson, you can learn:
- What is a class?
- Interface and Implementation
- Accessibility within a class
- Code example for custom class
- Class Method VS Instance Method
- Synthesized Accessors methods
- Direct Access to Encapsulated Data
- Dot Notation
<What is a class?>
Objects consists of data variables and functions (called methods).
A class defines what an object will look like when it is created. If defines what the methods will do and what the member variables will be.
Before an object can be instantiated we first need to define the class "blueprint" for the object.
An Objective-C class is defined in terms of an interface and implementation.
The syntax for the interface section of a class is as follows:
@interface NewClassName : ParentClass{ ClassMembers; // defines instance variables } ClassMethods; @end |
For example,
@interface BankAccount: NSObject{ double accountBalance; long accountNumber; } @end |
<Interface and Implementation>
In Objective-C, there are separated into two sections for one class: interface (also called header file) and implementation.
#import <UIKit/UIKit.h> @interface MyClass : NSObject{ // instance variable declarations go here before iOS 5.0 ... } @property (nonatomic, strong) double height; // Property // instance method? - (NSString*) sayHi; @end |
#import "MyClass.h" @implementation MyClass{ // instance variable (ivar) declarations go here starting with LLVM, but not header file, as header file has "public" access by others // compiler version 3.0 (Xcode 4.2 and later) ... } - (NSString*) sayHi{ return @"Hello world!!!"; } @end |
Notes:
NSObject is not the only Cocoa base class. But usually all classes are derived from the base class NSObject, which is the superclass of all Objective-C classes. It provides basic methods like memory allocation and initialization.
To swap between Interface (MyClass.h) and Implementation (MyClass.m) in Xcode, we can click Navigate --> Jump to Next Counterpart.
<Accessibility within a class>
The Interface file is used to declare methods, it is usually visible to other classes, but there is no reason why instance variables need to be visible to other classes, as they are usually private.
Usually, the header file imports the basic header file for the entire Cocoa framework; in the face of an iOS program, that's UIKit.h. There is no need for the implementation file to import UIKit.h, because the header file imports it, and the implementation file import the header file. If a class needs to know about another class that isn't already imported in this way, its implementation file imports that class's header file.
The Implementation file is imported with its interface file as the full class definition. What's inside a class's implementation file is private to that class. If something about a class needs to be public, such as a method that you want other classes to be able to call, it is declared in the header file, and other classes import that header files in their implementation files.
The result of this arrangement is that everything has the right visibility. No implementation file (.m file) will be imported by other implementation file (.m file), but only header file (.h file);
Github: What is the difference between importing header files in “header file” and “implementation file”?
#import <UIKit/UIKit.h> @interface MyClass : NSObject // instance method? - (NSString*) sayHi; @end |
#import "MyClass.h" #import "OtherClass.h" @implementation MyClass{ // instance variable declarations go here starting with LLVM compiler version 3.0 (Xcode 4.2 and later) ... } - (NSString*) sayHi{ return @"Hello world!!!"; } @end |
<Code example for custom class>
Class methods are preceded by a plus [+] sign in the declaration and instance methods are preceded by a minus [-] sign.
If data needs to be passed through to the method (referred to as arguments), the method name is followed by a colon (:)
Choose the template with Command Line Tool |
Set project name as "bank" |
Build setting for the project "bank" |
Create a new file ... |
Create new Objective-C class |
Set the Objective-C class named as bankAccount |
For example, declare instance variables and instance methods in interface file (i.e. bankAccount.h)
#import <Foundation/Foundation.h>
@interface bankAccount : NSObject{
double accountBalance;
long accountNumber;
}
-(void) setAccount: (long) y andBalance: (double) x;
-(void) setAccountBalance: (double) x;
-(double) getAccountBalance;
-(void) setAccountNumber: (long) y;
-(long) getAccountNumber;
-(void) displayAccountInfo;
@end
|
Define the implementation file (i.e. bankAccount.m)
#import "bankAccount.h"
@implementation bankAccount
{
accountNumber = y;
accountBalance = x;
}-(void) setAccountBalance: (double) x{
accountBalance = x;
}-(double) getAccountBalance{
return accountBalance;
}
accountNumber = y;
}
return accountNumber;
}NSLog(@"Account Number %ld has a balance of %f", accountNumber, accountBalance); }
@end
|
Write the main function as below:
#import <Foundation/Foundation.h>
#import "bankAccount.h"
int main(int argc, const char * argv[])
{
@autoreleasepool {
// Create a variable to point to our class definition bankAccount
bankAccount *account1;
// Allocate memory for the class instance and initialize the instance
account1 = [[bankAccount alloc] init];
// Set account number
[account1 setAccountNumber: 123-123456-888];
// Set account balance
[account1 setAccountBalance: 1500.53];
// Call the method to display the values of the instance variables
[account1 displayAccountInfo];
// Set both account number and account balance
[account1 setAccount: 124-999999-883 andBalance: 2000.45];
// Output values using getter methods
NSLog(@"Number = %ld, Balance = %f", [account1 getAccountNumber], [account1 getAccountBalance]);
}
return 0;
}
|
Compile & Run the project [ERROR]:
Reason: the Account Number is set "123-123456-999" is oversize as long data type.
Fix it!
Reason: the Account Number is set "123-123456-999" is oversize as long data type.
Fix it!
// Set account number
[account1 setAccountNumber: 34543212];
// Set both account number and account balance
[account1 setAccount: 99912345 andBalance: 2000.45];
|
Compile and Run:
Log output |
<Class Method VS Instance Method>
Class methods work at the class level and are common to all instances of a class. While each of instance of the class will have its own instance variables containing corresponding instance specific values these methods clearly only operate at the instance level of the class.
In the above example, we can write a class method that will count the number of instances of the BankAccount class that have been initiated:
To do this we are going to write a new alloc method for class called newAlloc. The ingredients we need to achieve this are as follows:
- A declaration for a class method named newAlloc in the @interface section in order to increments the current value of the openAccounts integer before calling the standard alloc class method and returning a pointer to the allocated memory space.
- A declaration for a class method named totalOpen to return the current value of the instance count in the @interface section
- In implementation file, a static variable named openAccounts accessible to all class instances to store the istore the count of BankAccount instances and initialise it to 0.
- Implementations of the two new class methods in the @implementation section
- In main function, some code to create instances of the class using the newAlloc method and to obtain and output the instance count
#import <Foundation/Foundation.h>
@interface bankAccount : NSObject
{
double accountBalance;
long accountNumber;
}
+(bankAccount *) newAlloc;
+(int) totalOpen;
...
@end
|
#import "bankAccount.h"
@implementation bankAccount
openAccounts++;
return [bankAccount alloc];
}
return openAccounts;
} |
#import <Foundation/Foundation.h>
#import "bankAccount.h" {
@autoreleasepool {
// Creat
e 2 variables to point to our class definition bankAccountbankAccount *account1, *account2;
// Allocate memory for the 2 class instances and initialize the instances
account1 = [[bankAccount alloc] init];account2 = [[bankAccount alloc] init];
...
}return 0; } |
Compile and Run, but why the number of bankAccount instances = 0.
Since the memory allocation initialization for these 2 class instances are called "alloc" class method derived by NSObject class, not called "newAlloc" class method we declared.
#import <Foundation/Foundation.h>
#import "bankAccount.h" {
@autoreleasepool {
// Creat
e 2 variables to point to our class definition bankAccountbankAccount *account1, *account2;
// Allocate memory for the 2 class instances and initialize the instances
account1 = [[bankAccount newAlloc] init];account2 = [[bankAccount newAlloc] init];
...
}return 0; } |
Compile and Run again , thus the number of bankAccount instances = 2.
<Synthesized Accessors methods>
Accessor methods (also referred to as getters and setters) are methods belonging to a class that allow the programmer to get and set the values of instance variables contained within that class.
In our BankAccount example covered in the previous chapter we wrote accessor methods to get and set the bank account number and bank balance variables.
Fortunately, Objective-C provides a mechanism that automates the creation of accessor methods. These are called synthesized accessor methods and are implemented through the use of the @property and @synthesize directives.
The following code demonstrates a modified version of our BankAcount class @interface definition with the two getters and setters we original wrote removed and replaced by @property directives:
#import <Foundation/Foundation.h>
{ double accountBalance; long accountNumber; } +(int) totalOpen; @property long accountNumber;
@end
|
#import "bankAccount.h"
@implementation bankAccount
openAccounts++;
return [bankAccount alloc];
}
return openAccounts;
}NSLog(@"Account Number %ld has a balance of %f", accountNumber, accountBalance); }
@end
|
#import <Foundation/Foundation.h>
#import "bankAccount.h" {
@autoreleasepool {
// Create 2 variables to point to our class definition bankAccount
bankAccount *account1, *account2;
// Allocate memory for the 2 class instances and initialize the instances
account1 = [[bankAccount newAlloc] init];account2 = [[bankAccount newAlloc] init];
// Set account number
[account1 setAccountNumber: 34543212];
// Set account balance
[account1 setAccountBalance: 1500.53];
// Call the method to display the values of the instance variables
[account1 displayAccountInfo];
// Set both account number and account balance
//[account1 setAccount: 99912345 andBalance: 2000.45];
// Output values using getter methods
//NSLog(@"Number = %ld, Balance = %f", [account1 getAccountNumber], [account1 getAccountBalance]);
return 0; } |
<Direct Access to Encapsulated Data>
In fact, it is quite common for developers to want to directly access an instance variable without having to go through an accessor method.
double accountBalance = [account1 accountBalance];
|
<Dot Notation>
For example, to the get current value of our accountBalance instance variable:
double accountBalance = [account1 accountBalance];
|
Dot notation can also be used to set values of instance properties:
account1.accountBalance = 6789.98;
|
<Controlling Access to instance variables>
By default, the instance method is called protected access.
When accessing a public instance variable from another class or any other code in a methods or function, the -> pointer operator notation is used.
For example:
<Class Methods>
You don’t have to do anything to create a class object. One class object for every class
your program defines is created for you automatically as the program starts up. (This
includes the classes your program imports, so there’s a MyClass class object because you
defined MyClass, and there’s an NSString class object because you imported UIKit.h
and the whole Cocoa framework.) It is to this class object that you’re referring when
you send a message to the name of the class. [Page 83]
- protected - Access is allowed only by methods of the class and any subclasses.
- private - Access is restricted to methods of the class. Access is not available to subclasses.
- public - Direct access available to methods of the class, subclasses and code in other module files and classes.
@interface
{
double accountBalance; long accountNumber; int accessCount; float interestRate;
}
|
When accessing a public instance variable from another class or any other code in a methods or function, the -> pointer operator notation is used.
For example:
account1->accountBalance = 12345.67;
|
<Class Methods>
You don’t have to do anything to create a class object. One class object for every class
your program defines is created for you automatically as the program starts up. (This
includes the classes your program imports, so there’s a MyClass class object because you
defined MyClass, and there’s an NSString class object because you imported UIKit.h
and the whole Cocoa framework.) It is to this class object that you’re referring when
you send a message to the name of the class. [Page 83]
No comments:
Post a Comment