IOS开发学习笔记Day1-OC基础一

简单类的声明与实现

#import <Foundation/Foundation.h>
// 类名后面的 :NSObject 是为了让我们的Iphone类具备创建对象的能力
@interface Iphone : NSObject
{
    //    注意: 默认情况下, OC对象中的属性是不能直接访问的
@public  // 只要让类中的属性公开, 以后就可以直接通过一个指向结构体的指针来操作对象中的属性
    float _model; // 型号  0
    int _cpu; // cup   0
    
}
// 行为
@end

// 2.如何编写类的实现
// 以@implementation开头, 以@end结尾, 然后在class对应的地方写上声明时声明的类的名称, 必须和声明的类名一模一样
@implementation Iphone
// 行为的实现
@end
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Iphone *p = [Iphone new];
        p->_model = 4;
        p->_cpu = 1;
        // OC中的类其实本质就是一个结构体, 所以p这个指针其实就是指向了一个结构体
        NSLog(@"model = %f, cpu = %i",p->_model, p->_cpu);
    }
    return 0;
}

类的方法

OC中的类方法用+表示, OC中的对象方法用-表示

#import <Foundation/Foundation.h>
// 类名后面的 :NSObject 是为了让我们的Iphone类具备创建对象的能力
@interface Iphone : NSObject
{
    //    注意: 默认情况下, OC对象中的属性是不能直接访问的
@public  // 只要让类中的属性公开, 以后就可以直接通过一个指向结构体的指针来操作对象中的属性
    float _model; // 型号  0
    int _cpu; // cup   0
    
}
// 行为
//类方法只能用类名调用, 对象方法只能用对象调用
//OC中的类方法用+表示, OC中的对象方法用-表示
- (void)about;
@end

// 2.编写类的实现
@implementation Iphone
// 行为的实现
- (void)about
{
    NSLog(@"打印本机信息");
    NSLog(@"model = %f, cpu = %i" , _model , _cpu);
}
@end
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Iphone *p = [Iphone new];
        p->_model = 4;
        p->_cpu = 1;
        //调用对象方法
        [p about];
    }
    return 0;
}

方法的调用

方法的调用本质上是向对象发送一条消息,语法如下:

oc中常规方式调用。

[对象 调用的方法或属性]

点语法

当OC中使用点语法时,默认会调用对象的geter和seter方法。
例如一个成员变量为length,则该变量get\set方法声明为setLengthlength方法。其调用语法如下
例如:

NSString *s = @"你好!";
//自动转换成[s length]
s.length;
//自动转换成 [s setLength]
s.length = 5;

有返回值,参数,多个参数,标签的方法

#import <Foundation/Foundation.h>

@interface Iphone : NSObject
//有返回值没有参数的方法
- (char *)startBoot;
//有返回值有一个参数的方法
- (char *)startBoot : (char *) argv;
//无返回值有两个参数的方法
- (void )startBoot : (int) startTime : (char *) argv;
//无返回值有两个参数的方法(带标签,使参数有更好的可读性)
- (void )startBootWithStartTime : (int) startTime argv: (char *) argv;

@end

// 2.编写类的实现
@implementation Iphone
- (char *)startBoot{
    return "start boot success!";
}
- (char *)startBoot:(char *) argv{
    return argv;
}
- (void )startBoot : (int) startTime : (char *) argv{
    NSLog(@"startTime = %i,argv = %s",startTime,argv);
}
- (void )startBootWithStartTime : (int) startTime argv: (char *) argv{
    NSLog(@"startTime = %i,argv = %s",startTime,argv);
}
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Iphone *p = [Iphone new];
        //调用对象方法
        char * c =      [p startBoot];
        NSLog(@"c = %s",c);
        
        c = [p startBoot:"start boot fail!"];
        NSLog(@"c = %s",c);
        
        [p startBoot:10 :"start boot"];
        [p startBootWithStartTime:10 argv:"start boot!"];
    }
    return 0;
}

类方法

直接通过类调用,不需要实例化类就可以调用的方法

#import <Foundation/Foundation.h>

@interface Iphone : NSObject
//类方法,直接通过类访问的方法,修饰符为 +
+ (char *)startBoot;

@end

// 2.编写类的实现
@implementation Iphone
+ (char *)startBoot{
    return "start boot success!";
}
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        char * c =      [Iphone startBoot];
        NSLog(@"c = %s",c);
    }
    return 0;
}

OC 中的字符串

字符串的申明与使用

NSString *s = @"你好!";
NSLog(@"%lu",[s length]);

代码标记,分割

在需要标记的地方使用#pragma mark 说明即可,#pragma mark -标记为一条长长的横线。
例如:

#pragma mark 主程序入口
int main(int argc, const char * argv[]) {
    return 0;
}

修改代码模版

修改项目模板以及main函数中的内容
/Applications/Xcode.app/Contents/Developer/Library/Xcode/Templates/Project Templates/Mac/Application/Command Line Tool.xctemplate/
修改OC文件头部的描述信息
/Applications/Xcode.app/Contents/Developer/Library/Xcode/Templates/File Templates/Source/Cocoa Class.xctemplate

开发文档安装

Xcode文档安装的位置1:
/Applications/Xcode.app/Contents/Developer/Documentation/DocSets
注意: 拷贝之前最好将默认的文档删除, 因为如果同时存在高版本和低版本的文档, 那么低版本的不会显示
Xcode文档安装的位置2:
/Users/你的用户名/Library/Developer/Shared/Documentation/DocSets
如果没有该文件夹可以自己创建一个

self关键字

相当于Java中的this关键字,谁调用的,self就是谁。

super关键字

和java类似,[super 调用的方法、属性]

description方法

相当于Java的toString。

私有变量

在实现(.m)中声明的私有变量其他类无法查看和赋值。

property、synthesize关键字自动生成getter、setter

@property 书写声明
@synthesize 书写实现

#import <Foundation/Foundation.h>

@interface Iphone : NSObject
@property int age;
@end

// 2.编写类的实现
@implementation Iphone
@synthesize age = _age;
@end

int main(int argc, const char * argv[]) {
    Iphone *p =   [Iphone new];
    [p setAge:10];
    NSLog(@"%d",[p age]);
    return 0;
}

:Xcode4.4后只需要声明@property可以直接生成getter、setter,也就是说不需要在实现中声明@synthesize。

property修饰符

@property修饰符有readwrite、readonly、getter、 setter,例如:
@property(readwrite) int age;
@property(getter=abc) double height;

动态数据类型id

id 是一个动态数据类型
例如:
id obj = [Student new];
常用判断方法 isMemberOfClassisKindOfClass,例如:

if ([obj isKindOfClass:[Student class]]) {
		// isKindOfClass , 判断指定的对象是否是某一个类, 或者是某一个类的子类
}
if ([obj isMemberOfClass:[Student class]]) {
		// isMemberOfClass : 判断指定的对象是否是当前指定的类的实例
}

new关键字实现原理

new做了三件事情
1.开辟存储空间 + alloc 方法
2.初始化所有的属性(成员变量) - init 方法
3.返回对象的地址

// Person *p = [Person new];
// alloc做了什么事情: 1.开辟存储空间; 2.将所有的属性设置为0 ;3.返回当前实例对象的地址
Person *p1 = [Person alloc];
// 1.初始化成员变量, 但是默认情况下init的实现是什么都没有做 2.返回初始化后的实例对象地址
Person *p2 = [p1 init];
// [[Person alloc] init];

// 注意: alloc返回的地址, 和init返回的地址是同一个地址
NSLog(@“p1 = %p, p2 = %p”, p1, p2);

// [[Person alloc] init]; == [Person new];
// 建议大家以后创建一个对象都使用 alloc init, 这样可以统一编码格式
Person *p3 = [[Person alloc] init];

构造方法实现的几个步骤

/*
// 重写init方法, 在init方法中初始化成员变量
// 注意: 重写init方法必须按照苹果规定的格式重写, 如果不按照规定会引发一些未知的错误
// 1.必须先初始化父类, 再初始化子类
// 2.必须判断父类是否初始化成功, 只有父类初始化成功才能继续初始化子类
// 3.返回当前对象的地址
- (instancetype)init
{
    // 1.初始化父类
    // 只要父类初始化成功 , 就会返回对应的地址, 如果初始化失败, 就会返回nil
    // nil == 0 == 假 == 没有初始化成功
    self = [super init];
    // 2.判断父类是否初始化成功
    if (self != nil) {
        // 3.初始化子类
        // 设置属性的值
        _age = 6;
        
    }
    // 4.返回地址
    return self;
}
 */

/*
- (instancetype)init
{
    self = [super init]; // self == nil == 0
    if (self) {
        // 初始化子类
        _age = 6;
    }
    return self;
}
 */
- (instancetype)init
{
//    self = [super init];
    // 注意: 不要把 = 号写为 ==
    // 一定要将[super init]的返回值赋值给self
    if (self = [super init]) {
        // 初始化子类
        _age = 6;
    }
    return self;
}

自定义构造方法

定义方法:

- (instancetype)initWithName:(NSString *)name{
    if (self  =[super init]) {
        _name = name;
    }
    return self;
}
- (instancetype)initWithAge:(int)age andName:(NSString *)name{
    if (self = [super init]) {
        _age = age;
        _name = name;
    }
    return self;
}

使用方式:Person *p2 = [[Person alloc] initWithAge:30 andName:@"lmj"];

自定义构造方法在继承中的表现

- (instancetype)initWithAge:(int)age andName:(NSString *)name andNo:(int)no{
    if (self = [super initWithAge:age andName:name]) {
        _no = no;
    }
    return self;
}

类工厂方法

根据苹果规范,实现了自定义构造方法后需要实现一个自定义的工厂方法用于产生对象。
例如:

+ (instancetype)person{
    return [[Person alloc] init];
}

注:上面方法在继承中会出现问题,因为创建方法制定类了。所以创建的对象也是指定类对象,所以我们需要用self关键字。

+ (instancetype)person{    
    return [[self alloc] init];
}

类的本质

类其实也是一个对象, 这个对象会在这个类第一次被使用的时候创建
只要有了类对象, 将来就可以通过类对象来创建实例对象
实例对象中有一个isa指针, 指向创建自己的类对象

类对象中保存了当前对象所有的对象方法
当给一个实例对象发送消息的时候, 会根据实例对象中的isa指针去对应的类对象中查找


Person *p = [[Person alloc] init];
[p setAge:30];
[Person test];

// 1.如何获取类对象
// [实例对象 class];  [类名 class];
Person *p1 = [[Person alloc] init];
Person *p2 = [[Person alloc] init];
// 一个类再内存中只有一份类对象
Class c1 = [p1 class];
Class c2 = [p2 class];
Class c3 = [Person class];
NSLog(@"c1 = %p, c2 = %p, c3 = %p", c1, c2, c3);

// 2.类对象的应用场景
// 2.1用于创建实例对象
Person *p3 = [[c1 alloc] init];
p3.age = 30;
NSLog(@"%i", p3.age);
// 2.2用于调用类方法
//    [Person test];
[c1 test];

类的启动过程

// 只要程序启动就会将所有类的代码加载到内存中, 放到代码区
// load方法会在当前类被加载到内存的时候调用, 有且仅会调用一次
// 如果存在继承关系, 会先调用父类的load方法, 再调用子类的load方法
+ (void)load{
    NSLog(@"Person类被加载到内存了");
}

// 当当前类第一次被使用的时候就会调用(创建类对象的时候)
// initialize方法在整个程序的运行过程中只会被调用一次, 无论你使用多少次这个类都只会调用一次
// initialize用于对某一个类进行一次性的初始化
// initialize和load一样, 如果存在继承关系, 会先调用父类的initialize再调用子类的initialize
+ (void)initialize{
    NSLog(@"Person initialize");
}

SEL类型

// 1.SEL类型的第一个作用, 配合对象/类来检查对象/类中有没有实现某一个方法
/*
SEL sel = @selector(setAge:);
Person *p = [Person new];
// 判断p对象中有没有实现-号开头的setAge:方法
// 如果P对象实现了setAge:方法那么就会返回YES
// 如果P对象没有实现setAge:方法那么就会返回NO
BOOL flag = [p respondsToSelector:sel];
NSLog(@"flag = %i", flag);

// respondsToSelector注意点: 如果是通过一个对象来调用该方法那么会判断该对象有没有实现-号开头的方法
// 如果是通过类来调用该方法, 那么会判断该类有没有实现+号开头的方法
SEL sel1 = @selector(test);
flag = [p respondsToSelector:sel1];
NSLog(@"flag = %i", flag);

flag = [Person respondsToSelector:sel1];
NSLog(@"flag = %i", flag);
*/


// 2.SEL类型的第二个作用, 配合对象/类来调用某一个SEL方法
/*
SEL sel = @selector(demo);
Person *p = [Person new];
// 调用p对象中sel类型对应的方法
[p performSelector:sel];

SEL sel1 = @selector(signalWithNumber:);
// withObject: 需要传递的参数
// 注意: 如果通过performSelector调用有参数的方法, 那么参数必须是对象类型,
// 也就是说方法的形参必须接受的是一个对象, 因为withObject只能传递一个对象
[p performSelector:sel1 withObject:@"13838383438"];

SEL sel2 = @selector(setAge:);
[p performSelector:sel2 withObject:@(5)];
NSLog(@"age = %i", p.age);

// 注意:performSelector最多只能传递2个参数
SEL sel3 = @selector(sendMessageWithNumber:andContent:);
[p performSelector:sel3 withObject:@"138383438" withObject:@"abcdefg"];
*/

猜你喜欢

转载自blog.csdn.net/lijianbiao0/article/details/89361709