首页 > 学院 > 开发设计 > 正文

Objective-C学习之路-由浅入深

2019-11-09 15:50:29
字体:
来源:转载
供稿:网友

一、Objective-C简介

Objective-C 简称OC /Obj-c Objective 是面向对象的,OC是在C语言的基础上添加了一些新的面向对象的语法,比较繁琐的语法封装的更为简单,所以在学习Objective-C之前大家必须去学习C语言一些基本的语法之类,这里我也写了C语言的学习博客,去学习C语言,大家可以参考一下。 所以OC它是完全兼容C语言的,我们可以在任何的OC语言中写任意的C代码。


二、Objective-C的第一个Hello World

#import <Foundation/Foundation.h>int main(int argc, const char * argv[]) { @autoreleasepool { // insert code here... NSLog(@"Hello, World!"); } return 0;}

学习的知识点: 1.main函数仍然是程序的出入口, 2.使用NSLog()函数进行打印输出, 3.@”“表示一个字符串


三、#import 的介绍

在学习了C语言之后,我们知道如果想要 引用系统中的头文件使用:#include<XXXX> 引用自己定义的头文件使用:#include “xxxx” 而在OC中使用的是#import,那么引入#imPRot有什么好处呢?

首先我们分别创建一个a.c和b.c文件并分别自动生成一个a.h和b.h的头文件: a.h中添加#include “b.h”

#ifndef a_h#define a_h#include <stdio.h>#include "b.h"#endif /* a_h */

b.h中添加#include “a.h”

#ifndef b_h#define b_h#include <stdio.h>#include "a.h"#endif /* b_h */

这种现象叫做重复包含,然后: 这里写图片描述 这里写图片描述 发现我们的include会报错,然后我们改成import: 这里写图片描述 这里写图片描述 会发现我们的报错就消失了,这到底是为了什么呢? 首先我们在a.h与b.h中都是:

//#ifndef b_h//#define b_h//#endif /* b_h */

ifndef:表示如果不存在就引入b.h文件,存在就啥都不干 define:表示默认引入b.h文件 endif:结束语,否则不引入b.h

而我们的import: #import指令是#include指令的增强版,能实现include的功能

.

列表内容#include指令单独使用,可能会造成重复包含,要防止重复包含,用预编译指令配合才能防止重复包含。#import增强的点就是单独使用这个指令的时候,不会造成重复包含,同一个文件中,无论被#import多少次,在预编译的时候只会包含一次。#import指令的底层会自动判断这个文件是否包含,没有包含的时候才会包含#import指令包含的时候和#include一样,也分为#import “” ,例如我们例子中的#import “a.h”
文件搜索顺序:先从当前文件夹下-->编译器的文件夹下-->系统文件夹-->查找失败 #import <>,例如我们例子中的#import 

四、NSLog()、NSString、NS前缀介绍、@符号介绍:

1、NSLog():C语言中的printf中的增强版 作用:在控制台打印数据 这里写图片描述 好处:打印清晰,不用输入/n,会自动换行

2、NSString():OC中特意设置了NSString指针去储存字符串,使用NSString指针变量可以保存1个字符串数据的地址。

注意: 一、OC字符串OC字符串必须以@开头 二、@必须写在”“前面 三、在OC中打印字符串使用%@ 四、 NSString只能储存字符串数据地址

例如:

这里写图片描述

与C语言相比增加了一个@。

3、NS前缀():

前缀:在OC应用中所有的类名都必须是全局唯一的,由于很多不同的框架会有一些相似的功能,所有在名字上也会有重复的可能,所以苹果官方文档规定类名需要2-3个字母作为前缀。 类前缀: 苹果官方建议两个字母作为前缀的类名是为官方的库和框架准备的,而对于作为第三方开发者的我们,官方建议使用3个或者更多的字母作为前缀去命名我们的类。 NS来自于NeXTStep 的一个软件 NeXT Software.OC中不支持命名空间,NS是为了避免命名冲突而给的前缀,看到NS前缀就是知道是Cocoa中的系统类的名称

4、@符号介绍:在OC中@符号有两种含义:

@”“:代表OC语言中的一个字符串,例如:@”你好世界”@直接接英文:代表OC语言中的一个关键字,例如:@interface

五、在OC中调用C代码:

这里写图片描述 以上我们是在OC中直接写C代码,现在我们来看下: 创建一个Show.c:

#include "Show.h"void showTest(){ printf("我是C语言写的,何人敢调用我啊/n");}

Show.h:

#ifndef Show_h#define Show_h#include <stdio.h>extern void showTest();#endif /* Show_h */

main.m: 这里写图片描述 我们在main中调用新创建的.c文件代码看到也是可以调用的。


六、OC中的布尔类型:

这里写图片描述 我们知道C语言中是没有布尔类型的,使用int类型去表示真假,2而OC提供了BOOL和Boolean去表示真假。


七、类的声明和实现

类:.h文件为类的声明文件,用于声明成员变量、方法。类的声明使用关键字@interface@end

注意:.h中的方法只是做一个声明,并不对方法进行实现,也就是说,只是说明一个方法名,方法的返回值类型、方法接受的参数类型而已,并不会编写方法内部的代码

.m:类的实现文件,用于实现.h中声明的方法,类的实现使用关键字@implementation@end

方法:方法的声明和实现,都必须以+或者-开头 +表示类方法(静态方法) -表示对象方法(动态方法)

成员变量:成员变量作用域有3中: 1.@public 全局都可以访问 2.@protected 只能在类内部和子类访问 3. @private 只能在类内部访问

这里写图片描述

这里写图片描述 以上我们可以看到: 1、类的声明:@interface 类名:父类类名(NSObject是所有类的父类) 2、类的实现:@implementaion 需要实现的类名

这里写图片描述

这里写图片描述


八、#pragma mark指令的使用,函数与对象方法的区别,常见注意点

这里写图片描述 当我们一个类中有大量代码,为了容易区分我们可以使用 #pragma mark 需要备注的信息

函数与对象方法的区别: 1.函数使用的时候直接调用,对象方法需要创建对象才能调用 2.函数不能放在声明中,对象方法的实现和声明只能方法在关键字练 3.函数不可以访问对象中的成员变量 4.对象方法归类所有

常见注意点: 1.实现和声明必须一一对应 2.@implementation、@interface、@end不能嵌套包含 3.成员变量必须写在{}里面,方法必须写在{}的外面 4.在声明时不能对类的成员变量初始化,请注意成员变量不能脱离对象而独立存在。 5.成员变量和方法不能使用static等关键字修饰,主要是不要和C语言混淆 6.类的实现可以写在main函数后面,在使用之前只要有声明就可以


九、NSString类简单介绍及用法

1.四种创建字符串的方式:

#import <Foundation/Foundation.h>int main(int argc, const char * argv[]) { @autoreleasepool { //1. NSString *name=@"张三"; NSLog(@"%@",name); //2. NSString *string = [NSString new]; string=@"李四"; NSLog(@"%@",string); //3. NSString *string2= [[NSString alloc] initWithFormat:name]; NSLog(@"%@",string2); //4. NSString *string3=[NSString stringWithFormat:@"图片 xxx %02d- %02d",0x13,10]; NSLog(@"%@",string3); } return 0;}

1.NSString字符串长度的计算方式:

NSString *str=@"abcdefg";NSLog(@"str的长度为:%ld",[str length]);//7

十、类方法介绍

前面我们说过用+修饰的代表类方法,例如: Person.h:

@interface Person : NSObject{ @public NSString *_name;}+ (void) show:(NSString *)name;- (void) showObj;@end

Person.m:

#import <Foundation/Foundation.h>#import "Person.h"@implementation Person+ (void) show:(NSString *)name{ NSLog(@"name=%@",name);}- (void) showObj{ NSLog(@"name=%@",_name);}@end

main.m:

#import <Foundation/Foundation.h>#import "Person.h"int main(int argc, const char * argv[]) { @autoreleasepool { Person *person=[Person new]; person->_name=@"我是通过对象来调用"; [person showObj]; [Person show:@"我是通过类调用的"]; } return 0;}

这里写图片描述

这里写图片描述


十一、self的用法

Student.h

@interface Student : NSObject- (void) study;- (void) eat;@end

Student.m

#import <Foundation/Foundation.h>#import "Student.h"@implementation Student- (void) study{ NSLog(@"我在学习啊。。"); [self eat];}- (void) eat{ NSLog(@"我在吃啊。。");}@end

main.m

#import <Foundation/Foundation.h>#import "Student.h"int main(int argc, const char * argv[]) { @autoreleasepool { Student *s=[Student new]; [s study]; } return 0;}

这里写图片描述


十二、description与Super的使用

Worker.h

@interface Worker : NSObject{ @public NSString *_name; int _num;}- (void)setName:(NSString *)name;- (NSString *)name;- (void)setNum:(int)num;- (int)num;@end

Worker.m

#import <Foundation/Foundation.h>#import "Worker.h"@implementation Worker/**- (NSString *)description{ return _name;}*/- (void)setName:(NSString *)name{ _name=name;}- (NSString *)name{ return _name;}- (void)setNum:(int)num{ _num=num;}- (int)num{ return _num;}@end

main.m

#import <Foundation/Foundation.h>#import "Worker.h"int main(int argc, const char * argv[]) { @autoreleasepool { Worker *worker=[Worker new]; worker->_name=@"张三"; NSLog(@"worker:%@",worker); } return 0;}

运行结果: 这里写图片描述

我们看到Worker.m中我们有一个description的方法,我们打开它然后运行: 这里写图片描述 这时候可以看到原本输出的地址值变成了我们description 方法中的值输出了 (NSString*) description 1.所有的类,都有description方法 2.作用:赋值NSLog输出

二、Super应用场景: 1.用在对象的方法中          调用对象父类的对象方法 2.用在类方法中          调用类的父类的类方法


十三、成员变量修饰符的介绍

成员变量修饰符: 1.@public :(公开)只要导入头文件,任何位置都可以使用 2.@protected:(半公开)可以在本类和子类当中进行访问(new出来的对象是调用不到的) 3.@private:(私有)只能在本类当中进行访问,子类无法进行访问赋值      @private修饰的成员变量子类不能直接访问,但是子类因为继承了这个@private修饰的成员变量,所以子类也不能重新定义这个成员变量。 4.@package:在同一框架内,可以直接访问


十四、多态的介绍

为什么父类可以访问子类继承自父类的方法,但是无法访问子类独有的方法? 1.编译器编译时: 编译器在编译时,只检查指针变量的类型,确定该指针变量类型里面有下面调用的方法,如果有该方法,编译器就认为,是正确的,可以编译通过。 2.运行时,会动态监测对象的真实类型,然后,调用对象自己的方法

父类指针,指向子类对象的这种形式,叫做多态。 当父类想要访问子类特有的方法时,强制类型转换。


十五、类对象

1.类代码存储在代码区。 2.当程序运行时,类第一次被访问,加载到代码区,这个加载类的过程称为类加载 3.类一旦加载到代码区之后,就一直不会释放,直到程序结束的时候才会被释放 4.任何数据存储于代码区,都有数据类型,那么类的数据类型什么呢?如何获取呢? main.m

#import <Foundation/Foundation.h>#import "Teacher.h"int main(int argc, const char * argv[]) { @autoreleasepool { Teacher *teacher=[Teacher new]; //第一种获取类对象的方法 Class c1=[teacher class]; //第二种获取类对象方法 Class c2=[Teacher class]; // c2= [Teacher new]; //[(Teacher*)c2 test]; [c2 show]; // c2->_num; NSLog(@"c1=%p,c2=%p",c1,c2); } return 0;}

总结: 1.类对象可以调用类方法 2.类对象可以创建出一个对象 3.不能用类对象调用方法 4.不能用类对象给成员变量赋值


十六、SEL的使用:

#import <Foundation/Foundation.h>#import "Person.h"int main(int argc, const char * argv[]) { @autoreleasepool { Person *per=[Person new]; //test为对象中的方法, //如果对象per中没有test方法就会报错 SEL s=@selector(test); //调用方式:[对象名 performSelector:SEL的变量名] [per performSelector:s]; } return 0;}

十七、点语法的使用

我们知道OC是面向对象的,所以必然有三大特性:封装,多态,继承,封装就是将我们的属性给封装起来使用set和get去得到属性 Person.h

@interface Person : NSObject{ @public NSString *_name; int _age; int _sex;}- (void)setName:(NSString*)name;- (NSString*)name;- (void)setAge:(int)age;- (int)age;- (void)setSex:(int)sex;- (int)sex;@end

Person.m

#import <Foundation/Foundation.h>#import "Person.h"@implementation Person- (void)setName:(NSString*)name{ _name=name;}- (NSString*)name{ return _name;}- (void)setAge:(int)age{ _age=age;}- (int)age{ return _age;}- (void)setSex:(int)sex{ _sex=sex;}- (int)sex{ return _sex;}@end

main.m

#import <Foundation/Foundation.h>#import "Person.h"int main(int argc, const char * argv[]) { @autoreleasepool { Person *p=[Person new]; p.name=@"张三"; p.age=10; p.sex=1; NSLog(@"name=%@,age=%d,sex=%d",p.name,p.age,p.sex); } return 0;}

点语法的本质就是set和get方法的调用


十八、@property、@synthesize关键字的使用

@property的作用:能够自动生成get和set方法的声明, 定义方式:@property 成员变量类型 成员变量名(去掉下划线) 在XCode4.4版本之前需要配合@synthesize使用

Person.h

@interface Person : NSObject{@public NSString *_name; NSString *name; int _age; int _sex;}/**- (void)setName:(NSString*)name;- (NSString*)name;- (void)setAge:(int)age;- (int)age;- (void)setSex:(int)sex;- (int)sex; */@property NSString *name;@property int age,sex;@end

Person.m

#import <Foundation/Foundation.h>#import "Person.h"@implementation Person@synthesize name,age,sex;@end

main.m:

#import <Foundation/Foundation.h>#import "Person.h"int main(int argc, const char * argv[]) { @autoreleasepool { Person *p=[Person new]; //这步能够调用,证明@property生成了set和get方法的声明 p.name=@"张三"; p.age=10; p.sex=1; //证明@synthesize生成了set和get的实现 NSLog(@"name=%@,age=%d,sex=%d",p.name,p.age,p.sex); } return 0;}

这里写图片描述

XCode4.4之后:

Person.h

@interface Person : NSObject@property NSString *name;@property int age;@property int sex;@end

Person.m

#import <Foundation/Foundation.h>#import "Person.h"@implementation Person@end

main.m:

#import <Foundation/Foundation.h>#import "Person.h"int main(int argc, const char * argv[]) { @autoreleasepool { Person *p=[Person new]; //这步能够调用,证明@property生成了set和get方法的声明 p.name=@"张三"; p.age=10; p.sex=1; //证明@synthesize生成了set和get的实现 NSLog(@"name=%@,age=%d,sex=%d",p.name,p.age,p.sex); } return 0;}

这里写图片描述


十九、了解动态类型和静态类型:

动态类型:程序知道执行时才能确定所属类,多态。Animal *anl=[Cat new]; 静态类型:将一个变量定义为特定类对象时,使用的是静态形态。Animal *anl[Animal new];


二十、id类型的使用

今天还有事,先写到这,持续更新


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表