目录
参考书:ios程序设计 Matt Neuburg
第一章 C语言的精髓
变量
C语言是强类型语言,所有变量都必须先声明并指定数据类型后才能使用。
结构体
原生数据类型、复合数据类型
指针
固定大小的整型变量,表示实际数据在内存中的位置。
C语言中:定义指向整型变量的指针intPTR后,*intPTR表希望该指针指向的整型变量--指针的解引用(简单理解为指向地址的数据内容),intPTR表指向的地址。
ObjC中:将指向对象的指针直接当成对象本身使用,所有与对象相关的ObjC代码均直接使用指针本身,而不是指针所知的对象。
指向void的指针,通用指针(void *),可以在需要任何特定类型的指针式用通用指针代替,通用指针避免了所指对象的类型检查,以下代码合法。
int* p1;// pretend p1 has a value
void* p2;
p2 = p1;
p1 = p2;
数组: NSArray的元素为对象
运算符
设置UIView的autoresizingMask时,用按位或 | 设置,Cocoa检查传入值哪些位为1设置样式(涉及enum,便于代码编写阅读)
流程控制和条件
1、for(before-all; condition; after-each) before-all:通常由于初始化计数器;condition:检查条件;after-each:一般由于增减计数器
2、ObjC引入BOOL类型,当需要用变量捕获或记录条件的值时,使用该类型以及YES和NO两个常量(实际表1和0)。避免把布尔变量同任何东西相比,甚至是YES和NO。eg:“2”这个值在表达式中也表示真,但既不等于YES也不等于NO。
函数
单独使用函数名是可能的,因为这个名字实际上也是一种变量。
文件
除非显示要求,一个文件中的代码不能自动“看到”另一个文件的内容,透明。显示要求#include -- .c, #import -- .m
预处理器指令
#define 名字 值 -- 避免“幻数”、宏定义(仅作文本代替)
#warning blabla -- 迫使Xcode在编译时产生一个警告信息
#pragma mark
数据类型限定符
const:在类型前面使用const表示这是一个常量,其值不能改变,变量必须在声明时进行初始化为其唯一可能的值(避免“幻数”)
static:使修饰的变量成为静态变量,所占的内存在函数返回后不会释放,值保持不变,供下一次函数调用时使用(返回单利)。
第二章 基于对象的程序设计
消息和方法
C语言程序中,所有的代码都属于某个函数。除非调用函数,否则这些代码不会执行。在基于对象的程序中,所有的代码隶属于某个对象,除非给对象发送消息(message),否则对象不执行代码。消息是一个对象给另一个对象的通知,而方法是调用代码,二者不一定一一对应(方法未实现?)。
类方法
类本身也是对象,可向类发送信息。类方法一般(但不是专门)用作工厂方法--生产实例的方法。
实例变量
实例具有代码和数据,实例的代码来源于所属的类,因而与该类的所有其他实例共享;但实例的数据只属于他本身。只要实例存在,数据就存在。实例在任何时刻都有自己的状态,即自己实例变量值的完整组合。实例是一种维持状态的机制、存储数据的盒子(容器)。
第三章 Objective-C对象和消息
实例应用、初始化和nil
对某些基于对象的编程语言来说,向nil发送消息会产生运行时错误,并导致程序崩溃。而在ObjC中,向nil发送消息是合法的,不会中断程序执行。如果尝试捕获消息的返回值,是0的某种形式。
消息和方法
1、类方法通过向类对象发送消息而调用,实例方法通过向它的实例对象发送消息而调用。ObjC方法名必须包含与参数数量相同多的冒号,在方法声明或调用中,名字在每个冒号后会隔开。因此,通常会在方法名前描述对应的参数。
2、向对象发送消息的语法遇到了方括号,方括号的第一部分内容是具体的对象,消息是向它发送的。这个对象称为消息的接受者(receiver)。方括号的第二部分是消息的名字。-- [receiver messageName]
3、方法的声明由三部分组成:
- 加号(+)或减号(-),分别表示方法是类方法或实例方法
- 方法返回的值类型,使用圆括号扩起来
- 方法名,使用冒号分隔开,每个冒号后是对应的参数,先使用一对圆括号将参数类型括起来,在指定参数名。
4、没有重载。方法返回值的数据类型,以及按顺序排列的每个参数的数据类型,组成了这个方法的签名(signature)。同一个类中,不能有两个同类型(类方法或实例方法)的同名方法具有不同的签名。
5、对象A不存在方法F,代码 -- [A F]
- 对于非ARC的编译器,代码合法,不会阻止运行,会产生两种警告:(1)代码中没有任何地方定义了F方法,Instance method 'F' not found(return type default to 'id');(2)代码中某个地方定义了方法F,'A' may nor respond to 'F'
- 对于使用ARC的编译器,无法通过编译,Receiver type 'A' for instance message does not declare a mothod with selector 'F'
类型转换和id类型
ObjC提供一个特殊的数据类型--id,用于避免编译器对任何对象数据类型产生的警告或者错误。id已经时指针,不需要使用*id,id含义为“对象指针”。任何消息都可以发送给一个id,但不代表程序编译或运行时一定不会发生错误。
nil是0的一种类型,是转换成id类型的0。向nil发送任何消息都不会让程序奔溃,而向实际对象发送未知的消息却会。
消息的数据类型
@selector()是变异器指令,告诉编译器圆括号内是消息名本身(不是NSString)。由于这是一个名字,因此其中不能包含任何空格,而且必须包含消息名中的所有冒号。
C语言函数
- 调用ObjC方法,向对象发送消息,使用中括号,并在方法名的每一个冒号后面指定实参。
- 调用C语言的函数,直接使用函数名,后面加一堆圆括号,其中包含每一个实参。
- NULL是C语言中的nil,表空指针;nil是id类型的0,NULL就是void*类型的0。NULL与nil在一定程度上可隐式互换,但并不完全相同。
CFTypeRef
NSString(类型NSString*的值)与CFString(类型为CFStringRef的值)可以互换 -- __bridge限定符。指向C语言数据类型结构体的指针名通常以“Ref”结尾,它们统称为CFTypeRef,实际上是指向void的通用指针。因此,经过桥接可以理解成在对象指针以及通用指针之间进行转换--广义上来说即,从id到void*转换或者从void*向id转换。就算某个对象没有与之对应的类型,总是可以在层次结构顶层找到对应的类型,即NSObject和CFTypeRef。
块对象
^(id obj1, id obj2) { }
第四章 Objective-C类
头文件和实现文件
头文件中包含类的接口部分,在实现文件只能够包含实现部分。
@class指令:在xx.m文件中import "MyOtherClass.h"(MyOtherClass的头文件),在xx.h文件中没有import "MyOtherClass.h"而使用 @class MyOtherClass,让编译器允许在头文件中使用MyOtherClass*。
第五章 Objective-C实例
创建实例有三种方式:1、现成的实例;2、从零开始的实例;3、基于nib实例化
1、现成的实例
通过调用能够进行实例化的代码简介实现,eg:
NSString * str = [@"asd" uppercaseString];
UIApplication * theApp = [UIApplication shareApplication];
2、从零开始的实例化
(1)使用alloc和initializar,alloc:为实例分配内存不能单独调用。initializer:初始化新建的对象。
要调用的初始化器是init,可以将连续的alloc和init方法缩短为new。即
MyClass * myclass1 = [MyCLass new];
MyClass * myclass2 = [[MyClass alloc]init];
(2)指定初始化器
如何类定义了多个初始化器,则在文档中可能将其中一个描述为指定初始化器(designated initializer)。没有定义指定初始化器的类继承其父类的指定初始化器;当某个类的父类链上没有其他指定初始化器时,它继承最基本的指定初始化器init。一切其他初始化器都依赖于指定初始化器,当前类或他的子类最终一定会调用指定初始化器。指定初始化器的参数必须最为丰富,应该允许调用方尽可能多地显示设置实例变量,而其他初始化器则会为了方便提供其中的一些实例变量的默认值。另一种情况是指定初始化器包含了最基本的初始化方式。自定义实现的指定初始化器的类会重写从父类中继承而来的指定初始化器。
3、基于nib初始化
使用nib文件或storyboard文件实现。
多态
当消息发送给一个对象时,重要的不是值向这个对象的指针声明成什么,而是这个对象本身是什么。对象本身是什么则有它所属的类以及它从父类链中继承的性质一起决定。这些信息属于对象本身,与指向它的变量如何展示自己无关。
self关键字
指的实际上是一个实例--“在此之前接受消息并导致代码最先遇到self关键字的实例”。
super关键字
主要目的是用于访问被覆盖的功能--通常把它用在重写某个功能的函数中,这样就可以即使用被覆盖的功能又使用新增的功能。
实例变量和存取器
存:setter,取:getter
键值编码(key-value coding)
将字符串转译成实例变量存取器的方法。
在键值编码中国,调用getter的方式为valueForKey: ,调用setter的方式为setValue: forKey: 。
属性
一种调用实例变量存取器的语法,只是调用存取方法的语法功能,不同于实例变量。
//
// Dog.h
// about_polymorphism
//
// Created by Dude on 2019/7/13.
// Copyright © 2019年 Dude. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface Dog : NSObject{
int age;
}
- (void)setAge:(int)age;
- (NSString *)speak;
- (NSString *)bark;
- (int)age;
@end
NS_ASSUME_NONNULL_END
//
// Dog.m
// about_polymorphism
//
// Created by Dude on 2019/7/13.
// Copyright © 2019年 Dude. All rights reserved.
//
#import "Dog.h"
@implementation Dog
- (void)setAge:(int)age{
self->age = age;
}
- (int)age{
return 100;
}
- (NSString *)speak{
return [self bark];
}
- (NSString *)bark{
return @"Woof!";
}
@end
//
// Basenji.h
// about_polymorphism
//
// Created by Dude on 2019/7/13.
// Copyright © 2019年 Dude. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Dog.h"
NS_ASSUME_NONNULL_BEGIN
@interface Basenji : Dog
- (NSString *)bark;
@end
NS_ASSUME_NONNULL_END
//
// Basenji.m
// about_polymorphism
//
// Created by Dude on 2019/7/13.
// Copyright © 2019年 Dude. All rights reserved.
//
#import "Basenji.h"
@implementation Basenji
- (NSString *)bark{
return @"emmm?";
}
@end
//
// main.m
// about_polymorphism
//
// Created by Dude on 2019/7/13.
// Copyright © 2019年 Dude. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Dog.h"
#import "Basenji.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Dog * d = [[Basenji alloc] init];
NSString * str = [d speak];
NSLog(@"str: %@", str); // str: emmm?
NSString * val = [d valueForKey:@"speak"];
NSLog(@"value For Key \"speak\": %@", val); //value For Key "speak": emmm?
[d setAge:10];
NSNumber * num = [d valueForKey:@"age"];
int age = [num intValue];
NSLog(@"age: %d", age); //age: 100
}
return 0;
}
书写初始化器
- (id)initWithNumber:(int)n{
self = [super init];
//(1)将初始化消息以调用指定初始化器。如果当前方法就是指定初始化器,把消息发送给super并调用父类的指定初始化器。否则A、[self 指定初始化器];B、[self 初始化器1];(初始化器1最终调用A)C、[self init];
//(2)捕获初始化消息返回的结果
if(self){
self->number = n;//(3)如果self不是nil,自定义初始化
}
return self;//(4)返回self
}