objective-c 语法快速过(4)

oc 里的字符串

字符串的快速创建(最简单的方法)

NSStirng *str = @“Hello”;//oc的字符串都是@“”形式的

oc的字符串也是类的对象,是NSString类的对象,创建没有那么麻烦不用[ ],使用面向对象的思想来操纵字符串。

 char *name = "xxxxx";//c风格字符串

oc使用 %@ 输出字符串,不是%s

NSString *name = @”dashuai”;



NSLog(@“我的名字是%@”,  name);

c 风格字符串输出解析的用法是%s

NSLog(@"%s", name);//%s是c风格的格式化解析

OC字符串的另一方式,Foundation 框架里的 NSString 类

NSString *newStr = [NSString stringWithFormat:@"My age is %d and no is %d and name is %@", age, no, name];



NSLog(@"---- %ld", [newStr length]); 
length方法,返回unsigned long类型
 NSString *name = @"哈哈达到";

// length方法算的是字数总数,包含的文字的数目!不是求字符个数!! 

int size = [name length];

不懂就去查询文档!百度!

 

//  main.m

#import <Foundation/Foundation.h>

/*

 NSString : 不可变字符串

 NSMutableString : 可变字符串

 */

int main()

{

    NSMutableString *s1 = [NSMutableString stringWithFormat:@"my age is 10"];

    // 拼接内容到s1的后面

    [s1 appendString:@" 11 12"];

    

    // 获取is的范围

    NSRange range = [s1 rangeOfString:@"is"];

    [s1 deleteCharactersInRange:range];

    

    NSString *s2 = [NSString stringWithFormat:@"age is 10"];

    

   //新建字符串,拼接好的字符串到新建的字符串里,但是原来的字符串没有变!两个方法不一样。

    NSString *s3 = [s2 stringByAppendingString:@" 11 12"];

    NSLog(@"s1=%@, s2=%@", s1, s2);

    

    return 0;

}



void stringExport()

{

    // 字符串的导出

    [@"Jack\nJack" writeToFile:@"/Users/apple/Desktop/my.txt" atomically:YES encoding:NSUTF8StringEncoding error:nil];

    

    NSString *str = @"4234234";



    NSURL *url = [NSURL fileURLWithPath:@"/Users/apple/Desktop/my2.txt"];



    [str writeToURL:url atomically:YES encoding:NSUTF8StringEncoding error:nil];

}



void stringCreate()

{

    /*

     1.字符串的创建

     */

    NSString *s1 = @"jack";

    

    //NSString *s2 = [[NSString alloc] initWithString:@"jack"];这种方法不推荐!

    

    NSString *s3 = [[NSString alloc] initWithFormat:@"age is %d", 10];

    

    // C字符串 --> OC字符串

    NSString *s4 = [[NSString alloc] initWithUTF8String:"jack"];

    // OC字符串 --> C字符串

    const char *cs = [s4 UTF8String];

    

    // NSUTF8StringEncoding 用到中文就可以用这种编码

    NSString *s5 = [[NSString alloc] initWithContentsOfFile:@"/Users/apple/Desktop/1.txt" encoding:NSUTF8StringEncoding error:nil];

    

    // URL : 资源路径

    // 协议头://路径

    // 本地文件   file://

    // ftp://

    // 网页资源 http://weibo.com/a.png

    // http://www.baidu.com

    

    // NSURL *url = [[NSURL alloc] initWithString:@"file:///Users/apple/Desktop/1.txt"];

    NSURL *url = [NSURL fileURLWithPath:@"/Users/apple/Desktop/1.txt"];

    

    NSString *s6 = [[NSString alloc] initWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];

    NSLog(@"s6=\n%@", s6);

    

    /*

     一般都会有一个类方法跟对象方法配对

     [NSURL URLWithString:<#(NSString *)#>];

     [NSString stringWithFormat:@""];

     [NSString stringWithContentsOfFile:<#(NSString *)#> encoding:<#(NSStringEncoding)#> error:<#(NSError *__autoreleasing *)#>]; 

     */

}

 

OC的 set 和 get 方法

类的成员变量尽量不要@public,保持数据的隐蔽性和封装性,使用对象直接访问类的成员变量也不推荐,因为这样类的成员变量可以被随意的修改,不安全,而是应该间接的调用。并且直接调用会让别人一下子就看到了类的内部结构和信息,失去了封装的意义。

set方法

1)   作用:用来设置成员变量,可以在方法里面过滤掉一些不合理的值

2)   命名规范:

  • 方法名都是以set开头,而且后面跟上成员变量名,成员变量名的首字母必须大写
  • 一定接受参数,且形参名称不要跟成员变量同名
  • 返回值void

get方法

1)   作用:返回对象内部的成员变量

2)   命名规范:get方法的名称一般就跟成员变量同名

/*成员变量的命名规范:一定要以下划线 _ 开头

@interface Student : NSObject

{ 

  1.让成员变量和get方法的名称区分开

  2.可以跟局部变量区分开,一看到下划线开头的变量,一般都是成员变量

  */

    int _no;

    Sex _sex;

}

// sex的set和get方法

- (void)setSex:(Sex)sex;

- (Sex)sex;

// no的set和get方法

- (void)setNo:(int)no;

- (int)no;

@end

oc特有的语法—兼容c系列的点语法 

可以使用点语法来代替oc古怪的对象调用的形式。这是oc特有的让其他(主要是习惯了 c 系列编程语言的程序员,比如 c,c++,java等)程序员快速看懂的一个做法。

 // 点语法的本质还是方法调用

    p.age = 10; // [p setAge:10];

objective-c 语法快速过(4)

objective-c 语法快速过(4)

这里还是古怪,到底是get还是set方法,要看是给它赋值了(set),还是被赋值了(get)。还是和java或c++的点语法区分。

oc 中类的成员变量的作用于

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

 @private : 只能在当前类的对象方法中直接访问。私有成员只能在本类被直接访问,子类不可见,只能是set和get方法访问(@implementation中默认是@private,因为一般不会包含实现文件,都是包含头文件,故实现文件默认是私有的

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

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

 @interface和@implementation中不能声明同名的成员变量,同名冲突,很好理解

Xcode的一个特性@property和@synthesize

sɪnθɪˌsaɪz v综合合成;(通过化学或生物)合成;(音响)合成

@property

自动生成set和get方法,类似java的eclipse的 setter 和 getter选项

#import <Foundation/Foundation.h>

@interface Person : NSObject

{

    int _age;

    int _height;

    double _weight;

    NSString *_name;

}

// @property:只能用在声明里,可以自动生成某个成员变量的setter和getter声明,并且和java还不一样,xcode把自动的声明隐藏,不可见。这是编译器的特性!

下面这一句,代表注释的那两句。

@property int age;

//- (void)setAge:(int)age;

//- (int)age;

@property int height;//先生成set再get

//- (void)setHeight:(int)height;

//- (int)height;

- (void)test;

@property double weight;

//如果成员变量类型一样,可以合并在一起写,但是实际开发不这样,分开比较好

@property NSString *name;

@end

注意:@property里的变量age如果没有被提前声明,那么也是可以运行的,编译器会自动生成_age成员变量,xcode4.4版本之后有的。这样生成的成员变量,在类声明里是@private。若类声明里存此成员变量,如果@property还是那么写,就不会再自动生成。

 @synthesize

只写在实现里。可以自动去类声明里找@property,然后根据它去生成类的成员变量的setter和getter方法的实现,并且会访问这个成员变量

@synthesize age = _age;

objective-c 语法快速过(4)

 如果这样写,默认会访问age这个成员变量,如果没有age,就会自动生成@private类型的age变量,都是自动存在类声明里。

注意:xcode4.4之后,为了让程序员把精力放在业务逻辑上,而不是无谓的垃圾代码的书写上,xcode变得越来越方便,做的东西也越多,现在可以省略类的成员变量的声明,直接@property就可以自动生成变量和配套的set与get方法的声明。同样,4.4之后,类的实现里,@synthesize也不用写了。也就是说,set和get的实现不用写。

意味着,现在的@property 声明,类声明里的@property默认做两个事情,即生成set和get的声明,也生成set和get的实现。当然,如果类声明里没有变量声明,那么还要做第三个事情,自动生成私有的成员变量。

Xcode原则就是:没有,我替你生成,有我就直接用。

这里就可以解释为什么苹果建议类的成员变量前面加下划线?

因为@property 的新特性:自从 xcode4.4之后,@property 就独揽了@synthesize 的功能,也就说,@proeprty 可以同时生成成员变量的 set,get 方法的声明和实现,两个都能。默认的情况下,set 和 get 方法的实现,会去访问下划线的成员变量,故要求类的声明里使用下划线的变量命名方式命名成员变量。说到底:就是因为新特性的@property自动生成set,get方法的声明和实现,默认访问的都是前面带下划线的成员变量。

oc 里的 id 类型(万能指针)

id 是一种类型

类型不能做变量名,好比 int  int;是错误的,一个道理。

Id 是万能指针

能指向(操纵)任何的 oc 对象,而且不能加*,只写id就代表指针(因为 id内部已经包含*,见官方文档)。

objective-c 语法快速过(4)

 Person *p = [Person new];//传统的操作人的对象,人类型指针p 指向人的对象

万能指针,id能指向 or 操作任何OC对象,只适合用在 oc 对象上

id d = [Person new];//id 指向人的对象      

id 的缺点:

如果同样是指向(调用)类不存在的对象方法,那么编译器直接报错!不会弱语法了

千万别加*

oc 的构造方法和重写 

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

面向对象的语言,都包含的东西---构造方法,用和 c++类似的new 这个类方法创建对象,其实不好。

// Person *p = [Person new];不推荐这样创建对象

new 其实是类方法,是 NSObject 类的方法,可以创建对象,分配内存,但是事实上,我们不常用,因为太死板,做的事情很单调,就是完整的创建一可用对象。

完整地创建一个可用的对象其实分两步:

 1.分配存储空间  +alloc

 2.初始化 -init

new 方法做这两个事情,new 方法内部,调用两个方法(一个类方法,一个对象方法)完成这个步骤,细节为:

1.调用+alloc分配存储空间

Person *p1 = [Person alloc];//此时对象不可用,没有初始化,返回 id(oc 对象)

2.调用-init进行初始化

Person *p2 = [p1 init];反回 oc 对象(已经初始化之后)本身

说明 new 是两个方法的联合,开发不常用,比较死板,一般分两步做,这样后果是方便选择。因为初始化不一定必须是 init对象方法初始化。。

两步合并的简单写法:掌握,开发常用这个写法,从此不用 new 了。

Person *p4 = [[Person alloc] init];

Oc的构造方法就是-init 方法,用来初始化对象的方法。对象方法,每个对象内部的成员变量默认都初始化为0,

创建 person 对象,保证她的_age 默认都是10,不是0,怎么做?

需要重写 –init方法,覆盖父类 –init方法

重写构造方法的目的:

为了让对象创建出来,成员变量就会有一些固定的值

重写构造方法的注意点

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

2.再进行子类内部成员变量的初始化,和 c++类似。

Person.h

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property int age;

@end



Person.m

#import "Person.h"

@implementation Person

// 重写-init方法,其实 id 有些类似 c++的模板的应用。

//- (id)init

//{

//    1、一定要先调用super的init方法:先初始化父类中声明的一些成员变量和其他属性

     self = [super init]; // 返回的是当前oc对象,一定用 self接受,这里需要好好研究,先知道。

//    2.如果父类对象初始化成功,才有必要进行接下来的初始化

//    if (self != nil)

//    { 

//        _age = 10;

//    }

//    

//    3.返回一个已经初始化完毕的oc对象

//    return self;

//}
//综合的写法,熟练之后如下这样写: - (id)init { if ( self = [super init] ) { _age = 10; } return self; } @end

要求:

学生类的学生对象,初始化完毕之后,年龄都是10,学号都是1.还是重写构造方法-init

Student.h继承 person 类

#import "Person.h"

@interface Student : Person

@property int no;

@end

Student.m #import "Student.h" @implementation Student // 学生对象初始化完毕后,年龄就是10,学号就是1 - (id)init { if ( self = [super init] ) { _no = 1; } return self; } @end

main.h #import <Foundation/Foundation.h> #import "Person.h" #import "Student.h" int main() { // 每个stu对象创建出来,他的_age都是10,学生学号都是1,isa 指向本身 每个 p4对象创建出来,她的 _age 都是10,isa 指向本身类 Person *p4 = [[Person alloc] init]; Student *stu = [[Student alloc] init]; return 0; }

student 继承了 person ,而 person继承了 NSObject,比如 student 对象内部有三个成员变量,分别为: student 自己的_no,和继承自父类 person 类的_age,还有 person 最开始就继承的父类NSObject 的 isa指针,这个三个成员变量,都是 student 对象 stu 包含的!

objective-c 语法快速过(4) 

因为student 类 创建 student 对象的时候,先进入 student 类查找-init,(因为 oc 里规定,如果父类和子类有同名方法,子类对象优先调用子类同名方法),然后 在 student 类里发现- (id)init方法,之后又发现:

{



    if ( self = [super init] )这句话,那么编译器会率先进入到父类 person,因为 super 的作用



    {



        _no = 1;



    }



    return self;



}

然后先调用直接父类 person 的 –init,而 person 的-init为:

- (id)init



{



    if ( self = [super init] )还是执行到此,我们发现调试就进不去了,因为 super 调用的是 NSObject,苹果是不开源的,但是事实还是进去偷着执行 NSobject 的-init 方法,初始化isa 指针, 把 isa 初始化为指向student 类本身,记住是当前的类,初始化完毕,程序执行回到 person 类,继续向下执行_age=10。(同时student 的成员变量 age 变为10)



    {



        _age = 10;



    }



    return self;最后返回的 self 指向的是 当前student 的对象



}

当person的-init 调用完毕,最后才回到 子类student 类,继续执行 student 的-init, 执行_no=1,继承来的 isa 初始化为指向本身 student 类,这才初始化完毕。

person 对象初始化的时候,同理,先在本类查找初始化方法,发现 super 语句,然后再去父类 NSObject 类 里查找-init方法,(这里先记住 self=[super init]的写法,下来再深入),NSObject 做一件事,那就是初始化 isa,把 isa 指向 person 类本身,(指向当前类,这个类是毕源的,看不到内部代码)然后回到 person类,_age=10。执行完毕。

objective-c 语法快速过(4)

再看一看 student 对象,创建的时候,先初始化,同理在本类,然后 发现 super,那么去父类 person 执行-init,还是发现 super,还是去 NSObject执行-init,把 isa 指向 student 类本身,(当前类不是 person,是 student 了)然后回到 person,_age=10.回到student,_no=1,执行完毕,再回main 函数,初始化,完毕。

oc构造方法的自定义

 oc自定义构造方法的规范

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

 2.返回值一般是id类型

 3.方法名一般以initWith开头

这让我想起了,c++构造函数的含参构造和默认构造,和不带参数的构造,意义是类似的。其实就是带参构造。和 c++大同小异。

Person.h

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property NSString *name;

@property int age;

- (id)initWithName:(NSString *)name;

- (id)initWithAge:(int)age;

- (id)initWithName:(NSString *)name andAge:(int)age;

@end



Person.m

#import "Person.h"

@implementation Person

- (id)initWithName:(NSString *)name

{

    if ( self = [super init] )固定写法,记住

    {

        _name = name;

    }

    return self;

}

- (id)initWithAge:(int)age

{

    if ( self = [super init] )

    {

        _age = age;

    }

    return self;

}

- (id)initWithName:(NSString *)name andAge:(int)age

{

    if ( self = [super init] )

    {

        _name = name;

        _age = age;

    }

    return self;

}

@end



Student.h继承 person 类

#import "Person.h"

@interface Student : Person

@property int no;//_no 是子类 student 自己的属性

- (id)initWithNo:(int)no;

- (id)initWithName:(NSString *)name andAge:(int)age andNo:(int)no;

@end



student.m

#import "Student.h"

@implementation Student

- (id)initWithNo:(int)no

{

    if ( self = [super init] )

    {

        _no = no;

    }

    return self;

}

// 要理解和接受这个做法和思想:

// 父类的属性交给父类方法去处理,子类方法处理子类自己的属性

- (id)initWithName:(NSString *)name andAge:(int)age andNo:(int)no

{

// 将name、age传递到父类方法中进行初始化,no 在本类初始化

使用了自定义的构造方法

    if ( self = [super initWithName:name andAge:age])

    {

        _no = no;

    }

    return self;

}

@end



main.m

#import <Foundation/Foundation.h>

#import "Person.h"

#import "Student.h"

int main(int argc, const char * argv[])

{

    @autoreleasepool {

        Student *p = [[Student alloc] initWithName:@"Jim" andAge:29 andNo:10];

    }

    return 0;

}

每个对象创建之后,都有一个默认名,年龄,和学号,但是每个人的结果不一样。此时,需要使用自定义构造方法初始化。否则重写构造方法初始化的话(不带参数)导致名称都是一样的。不符合程序要求。

首先,创建 student 对象,初始化对象指针 p(指向对象),先在本类找 initWithName 方法,确实有,然后进入执行,将name和age(都是继承来的属性)传到父类方法中进行初始化:这样分工明确(其实和 c++一样的思路),自己做自己的事情,体现了良好的架构思想,还有这样做的好处是,如果我们都统一在子类初始化,那么一旦父类的成员变量名称改变了,会导致子类的代码出错,需要修改,一旦工程较大,后果不堪设想,而分工明确,自己做自己的事情,把父类的成员让父类去初始化,子类只管自己的,就能做到不变应万变。

objective-c 语法快速过(4)

 

你可能感兴趣的:(Objective-C)