返回
编程
分类

它可以作为一个占位符表示这是一个不确定的类型的对象或者引用,OC当中方法名的表示方法和C

日期: 2019-11-20 06:35 浏览次数 : 133

【读书笔记】iOS-强类型与弱类型,读书笔记ios-类型

id类型是一个通用类型,OC使用id表示任意类型的对象,它可以作为一个占位符表示这是一个不确定的类型的对象或者引用。因此,所有的对象都 可以用id来表示。这很有用,想象一下,如果你需要实现一个通用的链表类,你可以将链表结点中的数据字段的类型声明为id类型,那么你就可以往这个链表中存放任意类型的对象了。

 

 

参考资料:《iOS编程指南》

id类型是一个通用类型,OC使用id表示任意类型的对象,它可以作为一个占位符表示这是...

OC是增强了C的特性,所以变量和基本数据类型上基本与C一致。
在OC中变量命名有如下规则:

  • 由字母、数字、下划线、$符号组成
  • 必须以字母、下划线、$符号开头
  • 大小写敏感

必威官网亚洲体育 ,目录

在OC中定义变量的时候不能使用OC的保留字,OC的保留字如下:

  • 成员变量
  • 方法的声明和实现
  • 方法的调用

必威官网亚洲体育 1

成员变量

注:本文演示的Demo,是基于《OC学习备忘录:类的定义》中的Demo

下面在WZKPerson类中定义姓名、年龄、民族、身高四个成员变量。

#import <Foundation/Foundation.h>

@interface WZKPerson : NSObject
{
     @private
     NSString *_name;
     NSInteger _age;
     @protected
     NSString *_nation;
     @public
     float height;
}
@end

下面对上述代码稍作解释。

  1. 成员变量定义在.h文件中,并且必须定义在类后面的{}中;
  2. @private、@protected、@public三个关键字可以控制成员变量的可访问性;
  3. @private表示变量为私有,只能在当前类中访问;
  4. @protected表示变量为受保护,只能在当前类或子类中访问(默认为@protected);
  5. @public便是变量为公共,所有类都可以访问;
  6. 通常声明@private、@protected的成员变量名称时,建议变量名前加下划线,而@public的成员变量名称前不需要;
  7. 变量名一般首字母小写,而类名一般首字母大写;

image

方法的声明和实现

上面已经声明好了成员变量,假设现在需要一个初始化姓名和年龄的对象方法、一个显示信息的对象方法、一个打印信息的类方法。

-(id)initWithName:(NSString *)name age:(NSInteger)age;
-(void)sayMyInfo;
+(void)printMessage:(NSString *)message;

下面对上述代码稍作解释。

  1. -号用来标识属于对象方法(类似于C#中的public方法),+号标识属于类方法(类似于C#中的static关键字);
  2. (id)和(void)是返回值类型的标识(C#中不需要括号来标识返回值,方法最后需要括号标识);
  3. OC方法的参数类型也需要放到()中,并且参数前必须使用冒号(冒号是方法名的一部分);

如果一个方法在.h中声明,则表示该方法为公共方法,如果直接在.m文件中定义则该方法是私有方法,外部无法进行访问;

另外需要注意,OC当中方法名的表示方法和C#完全不一样,以上述三个方法为例,方法名分别表示为:

  • -initWithName:age:
  • -sayMyInfo
  • +printMessage:

.h文件中方法声明好之后,就需要在.m文件中进行实现方法了。
#import "WZKPerson.h"

@implementation WZKPerson

-(id)initWithName:(NSString *)name age:(NSInteger)age
{
    self=[super init];
    if (self) {
        _name=name;
        _age=age;
    }
    return  self;
}

-(void)sayMyInfo
{
    NSLog(@"我叫 %@,今年 %li 岁",_name,_age);
}

+(void)printMessage:(NSString *)message
{
    NSLog(@"已经打印出:%@",message);
}
@end

上述代码中-initWithName:age:方法返回值类型为id,id在OC中其实就是一个指针,指向任何一个继承了Object(或者NSObject)类的对象,因此任意一个Object对象都可以是一个id。

注意:在使用id的时候不需要加星号,例如:id a=nil;

通常什么时机用id作为返回值类型呢?当不确定一个函数返回值能不能正常返回时使用,例如:-initWithName:age:方法中[super init]可能返回nil,而不是NSObject对象。

-initWithName:age:方法的返回值类型id可以用instancetype进行代替,instancetype是在clang3.5时提供的关键字,表示某个方法返回的未知类型的OC对象。

instancetype详细说明请参考:http://nshipster.com/instancetype/

NSLog()方法中的%@和%li属于占位符,下面列出一些常用的占位符。

占位符 说明
%i 以十进制形式输出整数,%hi输出短整型,%li输出长整型
%u 输出无符号整型(unsigned int)
%o 以不带符号八进制输出整型
%x 以不带符号十六进制输出
%c 输出一个字符
%f 以小数形式输出单精度、双精度浮点数,%lf长精度类型
%@ 输出一个字符串
%p 输出一个对象类型

关于占位符有几点需要注意的地方:

  1. OC中整型可以使用%i或者%d来格式化,只有使用scanf()输入的时候二者才有区别(由于%d始终被编译器解释为decimal intergeer所以即使输入010会被认为是整形10,而%i则会将前面的0或者0x认为此输入是八进制或十六进制整数);
  2. %p本质上就是输出指针地址,在32位编译器下对于一个指针类型使用%x输出和%p输出是一样的,只是后者会在前面加上0x,注意,在64位编译器下由于指针长度为8Byte,而整型只有4Byte,所以%x输出的内容只是%p的低位数据;
  • OC中有如下基本数据类型:
    int:声明整型变量
    double:声明双精度变量
    float:声明浮点型变量
    BOOL:声明布尔型变量
    char:声明字符型变量
    id:通用的指针类型
    enum:声明枚举类型
    long:声明长整型变量或函数
    short:声明短整型变量或函数
    signed:声明有符号类型变量
    struct:声明结构体变量
    union:声明共用体(联合)数据类型
    unsigned:声明无符号类型变量
    void:声明函数无返回值或无参
  • 数据类型格式化字符:(数据类型 oc关键字 格式说明引导符)
    整型 int %d.%i
    短整型 short int %hd.%hi
    长类型 long int %ld.%li
    无符号短整型 unsigned int %u
    无短整型 unsigned short %hu
    无符号长整型 unsigned long %lu
    浮点型 float %f
    双精度型 double %f
    长双精度型 long double %lf
    字符型 char %c

方法的调用

方法的声明和实现写好之后,就可以在其他类中进行使用了。

#import <Foundation/Foundation.h>
#import "WZKPerson.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        WZKPerson *zhangsan=[[WZKPerson alloc]init];
        [zhangsan sayMyInfo];

        WZKPerson *lisi=[[WZKPerson alloc]initWithName:@"李四" age:30];
        [lisi sayMyInfo];

        [WZKPerson printMessage:@"Hello"];
    }
    return 0;
}

下面对上述代码稍作解释:

  1. 如果想使用需要WZKPerson类,就需要引用类的头文件,#import "WZKPerson.h";
  2. WZKPerson *zhangsan=[[WZKPerson alloc]init]表示进行类对象的初始化工作,而C#中大多数使用new方式进行初始化,其实在OC中也可以通过new方式进行初始化,不过仅限于默认构造函数的方式进行,例如:WZKPerson *zhangsan=[WZKPerson new]。
  3. alloc表示分配一块内存空间,init(从NSObject中继承过来)表示进行初始化。
  4. WZKPerson *lisi=[[WZKPerson alloc]initWithName:@"李四" age:30]表示使用-initWithName:age:方法进行初始化。
  5. 一个类的对象方法和类方法通过在一个[]里面空格进行引用(而C#通过点进行调用);
  6. [WZKPerson printMessage:@"Hello"]表示类的类方法调用,类方法可以直接通过类名进行调用,与具体对象无关;

通常使用较多的是类的对象方法。

运行效果

必威官网亚洲体育 2

由于WZKPerson *zhangsan=[[WZKPerson alloc]init]使用的默认初始化,name和age使用的是默认值,因此调用sayMyInfo方法后,输出结果为“我叫 (null),今年 0 岁”。

必威官网亚洲体育 3


常用的一些占位符:

%@:字符串占位符

%d:整型

%ld:长整型

%f:浮点型

%c:char类型

%%:%的占位符

尽管有那么多的占位符,但是好像没有发现BOOL型的数据的占位符,这也是比较纠结的地方,看了一下别人是怎么解决这个问题的

BOOL studyBool = YES;

    NSLog(@"打印BOOL型数据

%@",studyBool?@"YES":@"NO");//;//)

打印BOOL型数据YES

    NSLog(@"打印BOOL型数据%d",studyBool);//打印BOOL型数据1

    BOOL alsoBool = NO;

    NSLog(@"打印BOOL型数据

%@",alsoBool?@"YES":@"NO");//;//)

打印BOOL型数据NO

    NSLog(@"打印BOOL型数据%d",alsoBool);//打印BOOL型数据0

详细介绍:**********************************************************

%@: Objective-C对象,印有字符串返回descriptionWithLocale:如果于的话,或描述相反.CFTypeRef工作对象,返回的结果的CFCopyDescription功能.(这个翻译有问题建议按照自己的理解方式理解)。

%%: 为'%'字符;

%d,%D,%i: 为32位整型数(int);

%u,%U: 为32位无符号整型数(unsigned int);

%hi: 为有符号的16位整型数(short);

%hu: 为无符号的16位整型数(unsigned shord);

%qi: 为有符号的64位整型数(long long);

%qu: 为无符号的64位整型数(unsigned long long);

%x: 为32位的无符号整型数(unsigned int),打印使用数字0-9的十六进制,小写a-f;

%X: 为32位的无符号整型数(unsigned int),打印使用数字0-9的十六进制,大写A-F;

%qx: 为无符号64位整数(unsigned long long),打印使用数字0-9的十六进制,小写a-f;

%qX: 为无符号64位整数(unsigned long long),打印使用数字0-9的十六进制,大写A-F;

%o,%O: 为32位的无符号整数(unsigned int),打印八进制数;

%f: 为64位的浮点数(double);

%e: 为64位的浮点数(double),打印使用小写字母e,科学计数法介绍了指数的增大而减小;

%E: 为64位的浮点数(double),打印科学符号使用一个大写E介绍指数的增大而减小;

%g: 为64位的浮点数(double),用%e的方式打印指数,如果指数小于4或者大于等于精度,那么%f的风格就会有不同体现;

%G: 为64位的浮点数(double),用%E的方式打印指数,如果指数小于4或者大于等于精度,那么%f的风格就会有不同体现;

%c: 为8位的无符号字符%c(unsigned char),通过打印NSLog()将其作为一个ASCII字符,或者,不是一个ASCII字符,八进制格式ddd或统一标准的字符编码的十六进制格式udddd,在这里d是一个数字;

%C: 为16位Unicode字符%C(unichar),通过打印NSLog()将其作为一个ASCII字符,或者,不是一个ASCII字符,八进制格式ddd或统一标准的字符编码的十六进制格式

[udddd](file:///udddd)

,在这里d是一个数字;

%s: 对于无符号字符数组空终止,%s系统中解释其输入编码,而不是别的,如utf-8;

%S: 空终止一系列的16位Unicode字符;

%p: 空指针(无效*),打印十六进制的数字0-9和小写a-f,前缀为0x;

%L: 在明确规定的长度下,进行修正,下面的一批数据a,A,e,E,f,F,g,G应用于双精度长整型的参数;

%a: 为64位的浮点数(double),按照科学计数法打印采用0x和一个十六进制数字前使用小写小数点p来介绍指数的增大而减小;

%A: 为64位的浮点数(double),按照科学计数法打印采用0X和一个十六进制数字前使用大写字母小数点P界扫指数的增大而减小;

%F: 为64位的浮点数(double),按照十进制表示法进行打印;

%z: 修改说明在%z长度以下d,i,o,u,x,X适用于某一指定类型的转换或者适用于一定尺寸的整数类型的参数;

%t: 修改说明在%t长度以下d,i,o,u,x,X适用于某一指定类型或一定尺寸的整数类型的转换的参数;

%j: 修改说明在%j长度以下d,i,o,u,x,X适用于某一指定类型或一定尺寸的整数类型的转换的参数。


常用的格式化输出:

  • %i和%d 无差别,%i是老式写法,%d是新式写法而已
  • %.2f 表示小数点后面数字保留两位
  • %4i 表示数字位数宽度。如数字1,那么结果是1,前面保留三位数
  • %04i 相比上面,是用0填补空位,即数字是1,那么结果是0001。这个在IOS开发中开帧动画可能有用,系列图片编号是001.png、002.png、003.png等。
  • %-4i 是有对齐,数字1,输出结果是1,后面保留三位。
#import <Foundation/Foundation.h>  

int main(int argc, const char * argv[])  
{  
    @autoreleasepool {  
        //保留字是不能定义为变量名的,例如下面的int、float等就不能作为变量名
        int i = 2;
        float f = 2.3f;
        double d = 2.3e12;
        char c = 'a';

        BOOL flag = true;
        NSLog(@"flag:%d",flag);
        //输出数据
        NSLog(@"i : %d",i);
        NSLog(@"f : %f 截取后 : %.2f",f,f);
        NSLog(@"d : %e 截取后 : %.2e",d,d);
        NSLog(@"c : %c , %d",c ,c );

        //数据转换
        //数据类型容量大的转成小的可能会丢失精度
        int i2 = (int)f;
        float f2 = (float)i ;

        NSLog(@"数据转换");
        NSLog(@"i2 : %d",i2);
        NSLog(@"f2 : %f",f2);

        int i3 = 0xffffff;
        NSLog(@"i3外面=%d",i3);
        NSLog(@"变量的作用域");
        if(YES){
            int i3 = 2;
            NSLog(@"i3 : %d",i3);
        }
    }  
    return 0;  
}   
/*
2017-12-07 10:31:16.517965+0800 function_func[35565:5466381] flag:1
2017-12-07 10:22:41.180474+0800 function_func[35464:5432868] i : 2
2017-12-07 10:22:41.181330+0800 function_func[35464:5432868] f : 2.300000 截取后 : 2.30
2017-12-07 10:22:41.181807+0800 function_func[35464:5432868] d : 2.300000e+12 截取后 : 2.30e+12
2017-12-07 10:22:41.181894+0800 function_func[35464:5432868] c : a , 97
2017-12-07 10:22:41.181944+0800 function_func[35464:5432868] 数据转换
2017-12-07 10:22:41.181960+0800 function_func[35464:5432868] i2 : 2
2017-12-07 10:22:41.181986+0800 function_func[35464:5432868] f2 : 2.000000
2017-12-07 10:22:41.182003+0800 function_func[35464:5432868] i3外面=16777216
2017-12-07 10:22:41.182011+0800 function_func[35464:5432868] 变量的作用域
2017-12-07 10:22:41.182018+0800 function_func[35464:5432868] i3 : 2
Program ended with exit code: 0
*/

id类型的介绍

id是一种通用的对象类型,她可以用类存储属于任何类的对象,可以理解为万能指针
***在id的定义中,已经包装好了*号,id指针只能指向os的对象
编译器看到id以后,认为是动态类型,不在检查类型

  • NSObject 和id都可以指向任何对象
    NSObject对象会惊醒编译时检查(需要强制类型转换)
    id不需要强制类型转换,id可以直接使用

  • instancetype与id异同
    相同点
    都可以作为方法的返回类型
    不同点
    1)instancetype可以返回和方法所在类型相同的对象,id只能返回位置类型的对象
    2)instancetype只能作为返回值,不能像id那样作为参数

#import <Foundation/Foundation.h>
#import"Dog.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        Animal *ani = [[Animal alloc]init];
        [ani run];//Animal在跑
        Animal *ani2 = [[Dog alloc]init];
        [ani2 run];//Dog 在跑

        NSObject *ob = [[Animal alloc]init];
        [(Animal*)ob run];//Animal在跑

        ob = [[Dog alloc]init];
        [(Dog*)ob run]; //Dog在跑

        //注意id使用
        //id类型的使用
        id obj2;
        obj2 = ani;
        [obj2 run]; //Animal在跑
    }
    return 0;
}

运算符介绍

  • sizeof() 是计算数据以及数据类型占用内存大小的运算符。
    • 如int num1 = sizeof(10) 或 int num1 = sizeof 10
    • 或先定义 float a =10.5 ,然后int num1 = sizeof(a) 或 int num1 = sizeof a
    • 但在计算数据类型是括号不能省略,即 int num1 = sizeof(float);
  • 逗号运算符:是输出最好一个运算结果,如 int b = (a=5,a++,a*6);结果b=36;
  • 关系运算符:真返回1,假返回0,且>、>=、<、<=的优先级高于==、!=,如果平级有时候从左向右运算。关系运算符优先级小于+-*/
  • 逻辑运算符:与或非&&、||、!。注意短路效应。

宏定义

#define RGBAlphaWrong(r, g, b, alpha)  [[UIColor colorWithRed:(r) / 255.0 green:(g) / 255.0 blue:(b) / 255.0 alpha:(alpha) ] set]

 RGBAlphaWrong(85, 26, 19, 0.5);  
参考:
  • Objective-C学习笔记 变量和基本的数据类型
  • Objective-C中的占位符,打印BOOL类型数据
  • id类型的使用与NSObject区别
  • Objective-C中的instancetype和id区别
  • ios常用#denfie
  • 进阶篇iOS常用的OC宏定义