iOS100

Exercise 2

"randomItems"

Objectives

Create a command line tool that generates an array of  "randomItem" objects and logs out randomly generated bits of information for each item  to the console.

Things you will learn...

  • Create a command line tool
  • Create and populate an array
  • Iterate though an array
  • Subclass an Objective-C class
  • Implement class and instance methods
  • Override methods
  • Implement Initializers
  • And  so much more!

End Result



Each item will contain:

  • Item Name
  • Serial Number
  • Value in Dollars
  • Timestamp


Step 1

Create a command line tool...

Setting up an array

  • Setup 5 objects
    • 1 NSMutableArray
    • 4 NSStrings
  • Remember: An array does not contain the objects that belong to it, only pointers to where those objects are stored in memory.


Things to remember...

  • NSMutableArray is a subclass of NSArray
    • It inherits most of its functionality from NSArray
  • Classes exist in a hierarchy
    • Every class has exactly one superclass
      • Except for the root class of the entire hierarchy
        • NSObject
    • A class inherits the behavior of its super class
  • Every class inherits the methods and instance variables defines in NSObject
    • alloc
    • init

Subclasses

  • Every subclass adds methods and instance variables to extend its superclass...
    • NSString - Adds behavior for storing and handling string, including the method "length"
    • NSArray - Adds behavior for ordered lists, including accessing an object at a given index w/ "objectAtIndex:"  and getting the number of objects in the array via "count"
    • NSMutableArray - Extends NSArray's abilities to add and remove pointers.



Lets create and populate the array...



Iterating over an array

  • Option 1
    • Traditional for loop
      • Leverage the count method in NSArray
      • Create a new NSString object every time you iterate
        • Access array element though "objectAtIndex:" or [ ]
  • Option 2
    • Fast enumeration
      • Shorter syntax
      • Less error prone
      • Has one limitation
        • Can not be used in conjunction with adding or removing items from an array




Loop though the items array...

Another way to view whats in an object...

Use the object pointer format string (%@) in NSLog()

This calls the "description" method on any object that is passed

By default, every subclass of NSObject (all objects) call the "description" method which returns an instance of NSString and replaces the %@ token.

Subclassing an Objective-C Class


Lets create a subclass of NSObject called "BNRItem"

BNRItem will represent something that a person owns in the real world like a laptop, bike, or backpack

BNRItem is going to act as a model class and hold data about our various possessions



Lets create our NSObject subclass...


BRNItem Class

  • BNRItem.h
    • Header file (AKA interface file)
    • Declares...
      • Name of the class
      • It's superclass
      • It's instance variables
      • Any methods that belong to the class
  • BNRItem.m
    • Implementation file
    • Contains all of the code for the methods that the class implements

Instance Variables

An item in the real world is going to contain...
  • Name
  • Serial Number
  • Value in Dollars
  • Date Created

Lets add them to our class!

Accessing Instance Variables

Need a way to access them...

Accessors!

"getters" & "setters"

Allow us to get and set the values of our instance variables though messaging

Without these, objects can access the instance variables of other objects...

Creating Getter & Setter Accessors...

  • In Objective-C the name of a setter method is "set" + the capitalized name of the instance variable

  • Getters are just named the same name as the instance variables

Implementing Getters & Setters...


  • Setters
    • Should set each instance variable = to the value of the variable passed into the method

  • Getters 
    • Should return the value of the instance variable


Lets add getter and setter methods to our class...
(Note: dateCreated should be readonly - Does not need a setter method)

Adding BRNItem to main.m


In order to use our custom subclass, 
we must import it into the main.m file

#import "BNRItem.h" 

Now lets use it!

What happened!?


When an object is created, all of its instance variables are "zeroed-out"  

Pointers to objects are made = nil

Primitives are set to their defaults such as 0


To make these variables more interesting, we have to pass arguments to their setter methods...

Using dot syntax


When using dot notation, the receiver (item) is followed by a "." followed by the name of the instance (valueInDollars)

This syntax is the same for both the getter and setter on an instance variable 

Using dot notation saves you from having to write a lot of boilerplate code!

Lets try it!

Overriding Methods

Subclasses can override methods of their superclass

One common example is overriding the description method inherited from NSObject

By default, this method returns the objects class and location in memory
 NSLog(@"%@", item.description) // displays "<BNRItem: 0x100102f80>"
This is usually not that helpful...

Lets override it to show a real description of the object...

Initializers

  • By default, every class has one way to initialize a new instance - the init method
  • Initializers take arguments that a class can use to setup an object for use  
  • You can add as many initialization methods as you want!
  • Each initializer should begin with the "init" prefix

Lets declare two initializers in our BRNItem header
  1. Takes thee arguments that it will use to configure the items name, value, and serial number
  2. Takes the items name and assigns the rest of the values defaults

The designated initializer...

No matter how many initializers you have, one must act as the designated initializer

The designated initializer makes sure that every instance variable of an object is valid

In the case of BRNItem, 
- (instancetype)initItemWithName:(NSString *)name valueInDollars:(int)value serialNumber:(NSString *)sNumber;  
should be the designated initializer since it is setting most of the instance variables defaults.

What is instancetype?

  • This keyword can only be used for return types

  • It is used to match the return type of the receiver

  • init methods always declare a return type of instancetype

  • This prevents conflicts with inheriting inits of the class in a different subclass


What about id?

id is defined as "a pointer to any object"

  • Unlike instancetype, id can be used as more then just a return type
  • It can be used for:
    • Return types
    • Variable declarations
  • Great for when you are unsure of what type of object the variable will end up pointing to
// Example: "item" could be any type of object...for (id item in items) {    NSLog(@"%@", items);}




Implement your designated initializer...

Things to note...


  • Always call the superclass's designated initializer using "super"

  • Always return a pointer to the successfully initialized object using "self"

What is "self"?

  • "self" is an implicit (predeclared) local variable automatically set to point to the object that was sent the message.
  • You should always return self in the last line of the init method so the caller can assign it to a variable
  • In most other languages it is known and used as "this"

Typically "self" is used so an object can send messages to itself:
 - (void)chickenDance{    [self pretendHandsAreBeaks];    [self flapWings];    [self shakeTailFeathers];}

What about "super"?

When you are overriding a method, you often want to keep what the method of the super class is doing and have your subclass add something new on top of that...

 - (void)someMethod{    [super someMethod];    [self doMoreStuffMethod];}

In BNRItem, the designated initializer is sending the init message to "super", which calls NSObjects implementation of "init"

Other initializers and the initializer chain


Note that this class already has a third initializer called "init" which it inherits from NSObject.

We must override "init" if we want to be able to use our own initializers....

Lets implement our second initializer "initWithItemName"

This initializer will only set the value of itemName and then set default values for the other arguments

Chain of initializers


Using initializers in a chain reduce the possibility of error and makes maintaining your code easier.

Simple initializer rules...

  • A class inherits all initializers from it super class and can add as many as it wants for its own purposes
  • Each class picks one initializer as its designated initializer
  • The designated initializer calls the superclass's designated initializer (directly or indirectly) before doing any initializing of its own
  • Any other initializers call the class's designated initializer (directly or indirectly).




Lets implement our initializers!

Class vs Instance Methods

  • Methods have two types
    • Instance
      • Operates on a particular instance of a class
      • Invoked by sending a message to a specific instance of a class
      • Example: init method
    • Class
      • Typically creates a new instance of the class or retrieves a global property of the class.
      • Invoked by sending a message to the class itself
      • Example : alloc method




Lets create a public class to generate random items!



Properties

What is a property?


  • Serves as a replacement for having to write getter and setter methods!
  • A property has three parts
  1. @property 
  2.  Property attributes
  3. Type and name

 @property (nonatomic, retain) NSArray *questions;


Property Attributes

  • Property attributes are special keywords to tell compiler how to generate the getters and setters. 

    • Thread Safety
      • All property declarations by default are "atomic" – meaning they are thread-safe.
      • However, in general, most applications are not multithreaded.  With that in mind, we the "nonatomic" attribute to indicate that the property accessor methods should not protect against thread safety.
@property NSString *someString; //Thread safe@property (atomic) NSString *someString; //Thread safe@property (nonatomic) NSString *someString; // NOT thread safe

Read/Write Attribute

  • Options
    • readwrite
      • Implements a getter and a setter method
    • readonly
      • Only implements a getter method

  • Default is set to readwrite

Memory Management

  • Describes the type of reference that the object with the instance variables has to the object that the variable is pointing to. 
    • strong
      • Specifies that there is a strong (owning) relationship to the destination object.
    • weak
      • Specifies that there is a weak (non-owning) relationship to the destination object.
      • If the destination object is deallocated, the property value is automatically set to nil.
  • Default is strong




Lets Implement Properties!




What did we learn today!?




Bonus

Run your application in the terminal!

"./randomItems"
Made with Slides.com