Artificial Intelligence + NLP + deep learning‎ > ‎OS‎ > ‎iOS‎ > ‎OLD‎ > ‎

Stanford Fall'13 Class


option+click     to see help for an item
in simulator press command-3 or 2 or 1 to see a miniature version
put all model files in Model folder that you create, then group them to a new group called Model

PROTOCOL: Blind way to talk to another object

 MVC

Controller -> Model
Controller -> View
View -> Controller:
Target/Action
Controller drops a Target on itself, hands-out action to view, implements Action to talk to Target.
when someone moves you or touches you send me that action.
Whenever sth happens, sends message to target
Blind, and simple structured way for view to communicate to controller
View -> Controller
Will/Should/Did
View delegates the answer to those questions to some other object
User just did scroll
User put down finger and touched the screen and will be scrolling
User touches down, should I scroll? am I allowed?
dataAt/count
view delegates answer to these questions to DataSource
Model -> BROADCAST
Notification/KVO (Key Value Observing)
Model broadcasts changes to anyone that might be interested. (in a like a wireless manner!!)
Controller can tune into that notification
 Multiple MVCs
Connections are either
the structured MVC connections within an MVC
OR one MVC as part of another MVC's view
OR shared memory (shared model) between MVC's

Files Types
.m     private stuff
.h      pubic API (what other people can call from you)

Import Classes

import any class used in a file
 If the superclass is in iOS itself, we import the entire framwork
@import <Foundation/NSObject.h>
BETTER to import entire framework(library)
@import <Foundation/Foundation.h>    ===    @import Foundation    //syntactic sugar for that

Objects are stored in heap and need reference counting to know when to release their memory. Primitive types are stored in stack
strong
 you want to "own" the object you are referencing with this property/variable, Only once you set the property to nil will the object get destroyed (unless one or more other objects also hold a strong reference to it).
weak
you don't want to have control over the object's lifetime. The object you are referencing weakly only lives on because at least one other object holds a strong reference to it. Once that is no longer the case, the object gets destroyed and your weak property will automatically get set to nil, instantly (not garbage collected later-on)!
Nil
You can send a message to nil, and it will return zero. (Nil == zero)  won't crash
if message returns struct, returns undefined

nonatomic
If you don't say nonatomic there is going to be all locking code for thread safety

@property

We do not directly access instance variables. Generate the getter/setter method and its header in both the .m and .h file

@interface in .h declares parent, in .m has ()

@synthesize
Rename property from its default _propertyName for internal purposes.
@synthesize propertyName = instanceVariableName;  // the default instance variable name for property contents is _contents
if you implement both getter/setter compiler warns, you need to declare @synthesize for it to make sure you did it on purpose
ALYWAS do validity checks for setters

ALWAYS do lazy initialization in getter.
Always initialize in getter to wait for the last minute, instead of initializing everything all at once in the beginning
+/- Class methods start with + Instance methods start with -
==  compares bare pointers not values.
when you have class name you must have *, you cant get memory address
No optional parameters for methods: if you want it you need to declare a separate method.

BOOL getter=isChosen   you can rename getter from this default

Sending Messages
[object      message_details]     general sending messages to objects (method calls)
- (void) addCard:(Card *) card atTop:(Bool)atTop;      //addCard:atTop: is the name of the method
object.property       only used for properties


Types

NSObject
- (NSString *)description   is like toString
NSLog(@“array contents are %@”, myArray); //===  [myArray description]
- (id)copy; // creates immutable copy (freezes e.g. array)
- (id)mutableCopy; // creates mutable copy
NSString *suit;
@"10"   literal string
return [NSString stringWithFormat:@"%d%@", self.rank, self.suit]    //create string (instead of init alloc)
// %d means number, %@ means object
return [rankString stringByAppendingString:self.suit];
NSString *sentence = [words componentsJoinedByString:@" "];   // sentence is now: @"This is a test"
NSUInteger rank;
Many people like to use NSUInteger and NSInteger in public API and unsigned int and int inside implementation. But be careful, int is 32 bits, NSInteger might be 64 bits. If you have an NSInteger that is really big (i.e. > 32 bits worth) it could get truncated if you assign it to an int. Probably safer to use one or the other everywhere
NSArray *rankStrings = @[1, 2, 3]; // array    All objects in the array are held onto strongly.
init
[[NSArray alloc] initWithObjects:...]
+ (id)arrayWithObject:(id)anObject;
NSArray *words = [NSArray arrayWithObjects:@"This", @"is", @"a", @"test", nil];
self.cards[index]   === [self.cards objectAtIndexedSubscript:index]    // returns id. just a syntactic sugar for arrays. Arrayindex out of bound

- (id)lastObject;       - (id)firstObject;    // returns nil (doesn’t crash) if there are no objects in the array
- (NSArray *)sortedArrayUsingSelector:(SEL)aSelector;
- (void)makeObjectsPerformSelector:(SEL)aSelector withObject:(id)selectorArgument;
- (NSString *)componentsJoinedByString:(NSString *)separator;

adding nil to NSMutableArray willl crash

NSMutableArray
init
+ (id)arrayWithCapacity:(int)count;
+ (id)arrayWithCapacity:(NSUInteger)numItems; // numItems is a performance hint only
+ (id)array; // [NSMutableArray array] is just like [[NSMutableArray alloc] init]
- (void)addObject:(id)object; // to the end of the array (note id is the type!) - (void)insertObject:(id)object atIndex:(NSUInteger)index;
- (void)removeObjectAtIndex:(NSUInteger)index;




Implicitly generated getter/setters:
@synthesize contents=_contents;
@synthesize chosen = _chosen;
@synthesize matched = _matched;

- (* NSString) contents //getter name is the same as the property
{
return _contents
}

- (void) setcontents(NSString *) contents
{
_contents = contentts
}

- (Bool) isChosen
{
return _chosen
}

- (void) setChosen(Bool)chosen
{
_chosen=chosen;
}

- (Bool) isMatched
{
return _matched
}

- (void) setMatched(Bool)chosen
{
_matched=matched;
}
Card.h
@import Foundation //import parent

interface Card : NSObject // declare public properties

@property (strong, nonatomic) NSString *contents;

@property (nonatomic, getter=isChosen) BOOL chosen; //rename getter
@property (nonatomic, getter=isMatched) BOOL matched;

- (int) match:(Card*) card;

@end
Card.m

#import "Card.h" //import header file

@interface Card() // declare private declarations

@end

@implementation Card

- (int) match(Card*)card
{
int score = 0;

//the object the message is beibg ssent to
//nam eof the message being sent
//argument being passed along with the message
if([card.contents isEqualToString:self.contents])
{
score=1;
}
return score;
}

@end

For other model files take a look at this git commit.
if([self.card count]){ //if not empty or null
if ([@[@"",@"",@"",@""] containsObject:suit]) {//override the setter to be sure no one tries to set it to something invalid.
    _suit = suit;

}

Initialization in Objective-C happens immediately after allocation.
Deck *myDeck = [[PlayingCardDeck alloc] init] always nest a call to init around a call to alloc

- (instancetype) init{
     self = [super init]
     if(self)   //don't assign anything to self except in init here -- check to make sure it is properly initialized/ not null
     {
                               PlayingCard *card = [[PlayingCard alloc] init];
     }
  return self;
}
}



1. Create single view Application.
View
Main.storyboard
Controller (generated by the prefix provided)
CardGameViewCntroller.m  
CardGameViewCntroller.h
Model
You need to write

Xcode

 
 


 
 
 
 
 
   

Create Controller action for View

Believe it or not, you connect your View to your Controller by directly dragging from objects in your View into your source code. Sounds crazy, I know ...
  • Hold down the ‘CTRL key’ while dragging the object into somewhere into your implementation block (between @implementation and @end)
  • Drag from your View to the header (.h) file of your Controller if you want to make a public connection (rare).
  • When you let go of the mouse, this dialog will appear. It wants to know some details about the ‘action’ message this button is going to send when touched.
    • Name
    • Type
      • We know that the sender of this action is a UIButton If this action could be sent from objects of another class (e.g. UISlider) we could leave the type “id” (which means an object of any (unknown) class).
    • Event
      • Normally buttons send their action when a touch that started by landing on them goes “up” while still inside the button’ boundaries. That’s what we want.
    • Arguments
      • Action methods are allowed to have either one argument (the object sending the message), no arguments, or even two arguments(the sender and the touch event provoking the action). In this case, though, what we want is just the sending button so that we can change it when it is touched.
click Connect to create the action method.
  • The name of this method is actually touchCardButton: not touchCardButton
  • This method’s return type is actually void, but Xcode uses the typedef IBAction instead just so that Xcode can keep track that this is not just a random method that returns void, but rather, it’s an action method. Apart from that, IBAction is exactly the same thing as void.
  • Mouse over object in View and the acions it conforms to will be highlighted.
UIImage has a class method called imageNamed: which creates an instance of UIImage given the name of an image in the image assets library. We just specify cardback (what we called the Stanford logo in the assets library).

press and hold run button to see run options.
Images
New Image Set in images.xcassetes, send in both normal and retina version.
UIImage *cardBack = [UIImage imageNamed:@"cardBack"];
[sender setBackgroundImage:cardBack forState:UIControlStateNormal]; 

Delete everything inside ViewController
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


So far we did react to what happened in view.
how the Controller can proactively communicate with an element of the View:
Hold down the CTRL key while dragging the mouse from the label to the code (then let go). Since we’re creating a @property here, we drag somewhere between the @interface and the @end
This @property we’re going to create is called an “outlet property” or “outlet” for short.

The @property created by this process is weak because the MVC’s View already keeps a strong pointer to the UILabel, so there’s no need for the Controller to do so as well. And if the UILabel ever left the View, the Controller most likely wouldn’t want a pointer to it anyway (but if you did want to keep a pointer to it even if it left the View, you could change this to strong (very rare)).

IBOutlet is a keyword Xcode puts here (similar to IBAction ) to remind Xcode that this is not just a random @property , it’s an outlet (i.e. a connection to the View). The compiler ignores it.

Check the connection between a View item and controller by right clicking on it.
You can “disconnect” connectoins by clicking on these little x’s.
OR right click on the yellowish square-in-circle icon at buttom of the mainstory editor and see connections.


Log to console

NSLog(@"here is a message for log %d", self.flipcount)

Model
1. when creating model files, Put all you models in a new folder 'model'
2. When classes are created; Select both Card.h and Card.m and then right-click on them to get this menu, then choose New Group from Selection.
Rename the group to model

Navigation

You can drag things around in the File Navigator to put them in whatever order you want.
For example, often we’ll drag the AppDelegate.[mh] into Supporting Files group since we rarely edit them

Be careful to choose both the Model folder . and the Model group in the Navigator.

readonly property does not have setter publicly

init
 initializers are instance methods that begin with “init” and return an object of the dynamic type id.
super = [super init];
if(self){
//if crashed somewhere here, self=nil; break;
}
return self;

instancetype / id

By using instancetype, you're saying that subclasses will return an object of the subclass. If we have

@interface Car

    +(instancetype)carWithWheels1:(NSArray *)wheels;
    +(Car *)carWithWheels2:(NSArray *)wheels;

@end
 
@interface VolkswagenBeetle : Car

@end

then +[VolkswagenBeetle carWithWheels1:] is guaranteed to return an instance of VolkswagenBeetle; but +[VolkswagenBeetle carWithWheels2:] might return a Buick, a Caddilac, or a ChittyChittyBangBang.

Use instancetype whenever it’s appropriate, which is whenever a class returns an instance of that same class.

There are certainly cases where you need to return id; namely, if you’re returning a different class. But you’ll probably use instancetype much more frequently than id.

static const int MAX_COUNT = 0;   //===equaivalent to #define

Outlet Collection

Outlet Collection arrays are always strong so Xcode has removed that option from the dialog. While the View will point strongly to all of the buttons inside the array, it will not point to the array itself at all (only our Controller will) so our outlet needs to be strongly held in the heap by our Controller.

Outlet collections are NSArray @property's
@property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *mortsdeck;    //IBOutletCollection(UIButton) is just something XCode puts in to remember that it's an outlet not just a random NSArray, the compiler ignores this.

Everything in Objective-C is dynamic binding (like id) but compiler checks for staticly typed variables and gives warnings if  a message send does not match with it's type.


mutablecopy     for NSArray/NSString
(Ship *) str      casting just tricks the compiler, doesn't do anything



create readonly in header file and redeclare it as readwrite in private interface in the implementation file.

Dynamic Binding


id
Pointer (not an object, that come with a star) to a class which we don't know its class.
id myObject; //pointer to an object I don't know its type.    

Ship *helloShip = (Ship *)hello;  // Casting doesn't run any code, just tricks compiler
[(id)hello shoot];     //ignore type of hello and regard it as bare id, no warning, thinks we know what we do

interospection

isKindOfClass:  whether an object is that kind of class (inheritance included): call class method of the class itself
if ([obj isKindOfClass:[NSString class]]) {
NSString *s = [(NSString *)obj stringByAppendingString:@”xyzzy”];
}

isMemberOfClass
:  whether an object is that kind of class (no inheritance)

respondsToSelector
:  responds to method

 if ([obj respondsToSelector:@selector(shoot)]) {
    [obj shoot];
} else if ([obj respondsToSelector:@selector(shootAt:)]) {
    [obj shootAt:target];
}
SEL is the Objective-C “type” for a selector
SEL shootSelector = @selector(shoot);     // SEL is the Objective-C “type” for a selector
SEL shootAtSelector = @selector(shootAt:);
SEL moveToSelector = @selector(moveTo:withPenColor:);

If you have a SEL, you can also ask objects to perform it
NSObject
[obj performSelector:shootSelector];
[obj performSelector:shootAtSelector withObject:coordinate];   //only one argument supported
NSArray - for all of its elements to run selector
[array makeObjectsPerformSelector:shootSelector];
[array makeObjectsPerformSelector:shootAtSelector withObject:target]; // target is an id
UIButton
- (void)addTarget:(id)anObject action:(SEL)action ...; [button addTarget:self action:@selector(digitPressed:) ...];

When used:
  • Mix objects of different classes in a collection (e.g. in an NSArray). Array returns id
  • To support “blind, structured” communication in MVC (i.e. delegation). And there are other generic or blind communication needs.



















Comments