iOS笔记之_OC特有语法

一、成员变量的作用域

@public : 在任何地方都能直接访问对象的成员变量。

@private : 只能在当前类的对象方法中直接访问(@implementation中默认是@private)。@protected: 可以在当前类及其子类的对象方法中直接访问  (@interface中默认就是@protected)。

@package : 只要处在同一个框架中,就能直接访问对象的成员变量。

 

@interface和@implementation中不能声明同名的成员变量。
例如:
#import <Foundation/Foundation.h>
@interface Person : NSObject
{
   int _no;
   
   @public // 在任何地方都能直接访问对象的成员变量
   int _age;
   
   
   @private  // 只能在当前类的对象方法中直接访问
    int _height;
   
   @protected // 能在当前类和子类的对象方法中直接访问
   int _weight;
   int _money;
}
 
- (void)setHeight:(int)height;
- (int)height;
 
- (void)test;
@end


二、@property和@synthesize

 

@property:可以自动生成某个成员变量的setter和getter声明

@synthesize自动生成age的setter和getter实现,并且会访问_age这个成员变量

例如:

#import<Foundation/Foundation.h>
@interfacePerson : NSObject
{
    int _age;
    // int age;
   
    int _height;
   
    double _weight;
   
    NSString *_name;
}
 
//@property:可以自动生成某个成员变量的setter和getter声明
@propertyint age;// 这一句可以代替下面的两行
//-(void)setAge:(int)age;
//-(int)age;
 
@propertyint height;
//-(void)setHeight:(int)height;
//-(int)height;
 
-(void)test;
 
@propertydouble weight;
 
@propertyNSString *name;
 
@end
 

三、构造方法

构造方法:用来初始化对象的方法,是个对象方法,-开头

重写构造方法的目的:为了让对象创建出来,成员变量就会有一些固定的值

重写构造方法的注意点

1.先调用父类的构造方法([super init])

2.再进行子类内部成员变量的初始化

 #import <Foundation/Foundation.h>
#import "Person.h"
#import "Student.h"
 
/*
 重写构造方法的注意点
1.先调用父类的构造方法([super init])
2.再进行子类内部成员变量的初始化
 */
int main()
{
   // Person *p = [Person new];
   /*
    完整地创建一个可用的对象
    1.分配存储空间 +alloc
    2.初始化 -init
    */
   
   // 1.调用+alloc分配存储空间
   // Person *p1 = [Person alloc];
   // 2.调用-init进行初始化
   // Person *p2 = [p1 init];
   
//   // 调用-init进行初始化
//   Person *p3 = [Person new];
   
/   
//   // 每个Person对象创建出来,他的_age都是10
   
   Person *p4 = [[Person alloc] init];
       
   Student *stu = [[Student alloc] init];
   
   NSLog(@"------");
   }
   return 0;
}


自定义构造方法的规范

 1.一定是对象方法,一定以 - 开头

 2.返回值一般是id类型

 3.方法名一般以initWith开头

四、分类

作用:在不改变原来类模型的前提下,给类扩充一些方法。

两种方式:

  分类

  继承

格式:

 分类的声明

@interface 类名 (分类名称)

// 方法声明

@end

  分类的实现

@implementation 类名 (分类名称)

// 方法实现

@end

使用注意:

 1.分类只能增加方法,不能增加成员变量

 2.分类方法实现中可以访问原来类中声明的成员变量

 3.分类可以重新实现原来类中的方法,但是会覆盖掉原来的方法,会导致原来的方法没法再使用

 4.方法调用的优先级:分类(最后参与编译的分类优先) --> 原来类  --> 父类

 // 优先去分类中查找,然后再去原来类中找,最后再去父类中找

5.多个Category中如果实现了相同的方法,只有最后一个参与编译的才会有效

 

四、类的本质

其实类的本质也是个对象,是Class类型的对象。

   1.当程序启动时,就会加载项目中所有的类和分类,而且加载后会调用每个类和分类的+load方法。只会调用一次。

    2.当第一次使用某个类时,就会调用当前类的+initialize方法

 

   3.先加载父类,再加载子类(先调用父类的+load方法,再调用子类的+load方法)

   先初始化父类,再初始化子类(先调用父类的+initialize方法,再调用子类的+initialize方法)

例如:

//Person.h文件:
 
#import <Foundation/Foundation.h>
 
@interface Person : NSObject
@property int age;
 
+ (void)test;
 
@end

//person.m文件
#import "Person.h"
 
@implementation Person
+ (void)test
{
   NSLog(@"调用了test方法");
}
  
// 当程序启动的时候,就会加载一次项目中所有的类。类加载完毕后就会调用+load方法
+ (void)load
{
   NSLog(@"Person---load");
}
 
// 当第一次使用这个类的时候,就会调用一次+initialize方法
+ (void)initialize
{
   NSLog(@"Person-initialize");
}
 
@end
  

#import <Foundation/Foundation.h>
#import "Person.h"
#import "Student.h"
#import "GoodStudent.h"
/*
 1.当程序启动时,就会加载项目中所有的类和分类,而且加载后会调用每个类和分类的+load方法。只会调用一次。
 
 2.当第一次使用某个类时,就会调用当前类的+initialize方法
 
 3.先加载父类,再加载子类(先调用父类的+load方法,再调用子类的+load方法)
   先初始化父类,再初始化子类(先调用父类的+initialize方法,再调用子类的+initialize方法)
 */
 
int main()
{
   // [[GoodStudent alloc] init];
   
   return 0;
}
 
void test1()
{
   Person *p = [[Person alloc] init];
   
   //[Person test];
   
   // 内存中的类对象
   // 类对象 == 类
   Class c = [p class];
   [c test];
   
   Person *p2 = [[c new] init];
   
   
   NSLog(@"00000");
}
 
void test()
{
   // 利用Person这个类创建了2个Person类型的对象
   Person *p = [[Person alloc] init];
   
   Person *p2 = [[Person alloc] init];
   
   Person *p3 = [[Person alloc] init];
   
   // 获取内存中的类对象
   Class c = [p class];
   
   Class c2 = [p2 class];
   
   // 获取内存中的类对象
   Class c3 = [Person class];
   
   
   NSLog(@"c=%p, c2=%p, c3=%p", c, c2, c3);
   
   //  类本身也是一个对象,是个Class类型的对象,简称类对象
   
   /*
     利用Class 创建  Person类对象
    
     利用 Person类对象创建 Person类型的对象
    
    */
}


五、description方法

 默认情况下,利用NSLog和%@输出对象时,结果是:<类名:内存地址>

    1.会调用对象p的-description方法。

    2.拿到-description方法的返回值(NSString*)显示到屏幕上。

    3.-description方法默认返回的是“类名+内存地址”。

  4.如果在-description方法中使用NSLog打印self,注意死循环。

六、SEL

SEL其实是对方法的一种包装,将方法包装成一个SEL类型的数据,去找对应的方法地址。找到方法地址就可以调用方法。消息就是SEL。

#import <Foundation/Foundation.h>
#import "Person.h"
 
int main()
{
   Person *p = [[Person alloc] init];
   
   [p test2];
   
//   NSString *name = @"test2";
//   
//   SEL s = NSSelectorFromString(name);
//   
//   [p performSelector:s];
   
   
   // 间接调用test2方法
   //[p performSelector:@selector(test2)];
   
   //[p test3:@"123"];
   
   
//   SEL s = @selector(test3:);
//   
//   [p performSelector:s withObject:@"456"];
   
   //[p test2];
   
   // 1.把test2包装成SEL类型的数据
   // 2.根据SEL数据找到对应的方法地址
   // 3.根据方法地址调用对应的方法
   return 0;
}


 

七、NSLog输出增强

   __FILE__ :源代码文件名

   __LINE__ :NSLog代码在第几行

   _cmd :代表着当前方法的SEL

// 下面的代码会引发死循环

- (void)test {

    [self performSelector:_cmd];

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值