iOS开发学习日志(1)

Objective-C语言基础学习总结  

目录

Objective-C语言基础学习总结  

1.学习环境和资源

2.Objective-C概览

(1)Objective-C

(2)头文件

(3)main函数

3.类

(1)类的声明和实现

类的声明

类的实现

(2)类的数据成员

属性Property

实例变量Instance Variable

(3)方法

全局函数

成员函数

消息发送

访问权限

初始化器和析构器

3.字符串NSString

(1)字符串NSString

初始化

常量性

共享机制

值相等和地址相等

NSMutableString

3.集合Collection

NSArray

初始化

常量性

遍历方法

数组查找


       这几天通过观看B站视频《iOS开发工程师 零基础到APP上线》,对OC的基础语言部分进行了系统学习,对OC语言的一些特性有了初步了解。在学习过程中,通过与C++中class对比,来加深自己的理解。接下来我会阅读官方文档《Programming with Objective-C》继续巩固语言,然后通过观看视频《iOS 7 应用开发》学习如何开发APP。

       下面是对近期学习的一个总结,巩固知识的同时,也能方便以后查阅(如有不正确的地方,欢迎大家批评指正)。

1.学习环境和资源

首先介绍一下我目前的学习环境、工具和几个学习iOS开发经常会访问到的一些网站以及相关书籍。

环境:因为我的电脑是Windows系统,所以只能安装虚拟机了,我安装的版本是:VMware Workstation Pro 15macOS 13

工具:Xcode 是运行在操作系统Mac OS X上的集成开发工具(IDE),可以直接在Apple Store下载,但是由于Apple Store中Xcode最新版本不支持macOS 13,所以我去官网http://developer.apple.com下载了Xcode 9(Xcode版本只能向上适配macOS版本,而不能向下)。

苹果社区:http://developer.apple.com,在这里可以找到官方文档,各个版本的系统软件等资源。

第三方网站:stackoverflow,Ourcoders, Cocoa China,Github。

书籍:苹果官方文档《Programming with Objective-C》,《Programming iOS 7》等。

2.Objective-C概览

(1)Objective-C

Objective-C是编写基于OS X和iOS系统软件的主要语言,它在C语言的基础上,实现了面向对象编程,具有封装、继承和多态特性。Objective-C是C语言的严格超集:任何C语言程序不经修改可以直接通过Objective-C编译器,Objective-C中使用C语言代码也是合法的。
Objetive-C代码的文件扩展名

扩展名

内容类型

.h

头文件。头文件包含类、类型、函数和常数的声明

.m

源代码文件。典型的源代码文件扩展名,可以包含Objective-C和C代码

.mm

源代码文件。带有这种扩展名的源代码文件,除了Objective-C和C代码,还可以包含C++代码。较少使用,除非代码中确实需要C++类或者特性时才用这种扩展名

(2)头文件

C++中使用#include添加头文件,而Objective-C中通过#import添加头文件。例如:

#import <Foundation/Foundation.h>

(3)main函数

Objective-C程序同样以main函数为入口。例如:

#import <Foundation/Foundation.h>

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

 @autoreleasepool {

      //insert code here....

     }

     return 0;

}

@autoreleasepool是自动释放池,整个块中内容支持ARC(Auto Reference Count自动引用计数),系统在资源引用计数为0时,自动释放资源,不需要手动释放(ARC有些类似C++11中的smarter pointer)。

3.类

(1)类的声明和实现

类的声明

通常会在头文件.h中声明一个类。与C++使用class来声明类不同,Objective-C中类的声明以@interface开头,以@end结尾,中间是数据成员和方法的声明。例如声明类RPoint:

@interface RPoint:NSObject

//添加数据和方法

@end

上述例子中SimpleClass是类名,该类继承自类NSObject。Objective-C中类名一般遵循首字母大写的原则,且程序员声明的类都应该继承自根类NSObject。因为NSObject中已经包含了类所需的分配器alloc、初始化器init、析构器dealloc等成员方法,继承后可直接调用。

类的实现

通常在与声明类的头文件同名的.m文件中实现类。C++中通过作用域符号来实现类中函数,而Objective-C中实现方法如下:

#import "PRoint.h"

@implementation RPoint:NSObject

//添加方法定义

@end

Objective-C只要声明了类,那么一定要实现它,即使实现代码块中不需要做什么。

(2)类的数据成员

属性Property

  • 属性表达实例状态,描述类型对外接口。相比直接访问实例变量,属性可以做更多控制。例如向上述RPoint类中添加属性:

@interface RPoint:NSObject

@property int x;

@property int y;

@end

  • 默认情况下,编译器会为属性定义的propertyName自动合成getter、setter访问器方法以及一个实例变量。类外可以使用属性访问,类内也可以通过self访问(self类似C++中this指针):

#import <Foundation/Foundation.h>

#import "RPoint.h"

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

 @autoreleasepool {

         //Objective-C中为对象动态申请内存,后面会细说 

          RPoint *rp1 = [[RPoint alloc] init];  

          rp1.x = 10;              //通过"."访问属性    

          rp1.y = 20;

     }

     return 0;

}

实例变量Instance Variable

  • 系统会为属性propertyName自动合成一个实例变量_propertyName,而getter和setter方法中访问的是_propertyName.。
  • 可以定义实例变量,而不定义属性。
  • 如果同时自定义了setter和getter访问器方法,或者针对只读属性定义了getter方法,编译器将不再合成实例变量。

注意:类外一律使用属性访问,类内通过self进行属性访问。只有以下情况使用实例变量访问:初始化器init,析构器dealloc,自定义访问器方法。

(3)方法

全局函数

  • 类以外定义的函数,NSLog就是一个全局函数。

成员函数

现在声明一个类BLNPoint,向其中添加实例方法和类型方法:

@interface BLNPoint:NSObject

@property int x;

@property int y;

//实例方法,无参数,无返回值

-(void) print;    

   //实例方法,有两个参数,无返回值                                           

-(void) moveToX:(int) x ToY:(int) y;    

  //类型方法,无参数,返回类型为BLNPoint      

+(BLNPoint *) getOriginPoint;                  

@end

以"-"开头的方法称为实例方法Instance method,通过类对象对其进行调用;而以"+"开头的方法称为类型方法Class method,类型方法类似于C++中的静态方法,直接通过类来调用。Objective-C类中方法默认是public。(21号从函数参数开始写起。。。)

消息发送

方法调用,即动态消息发送。例如:

#import <Foundation/Foundation.h>

#import "BLNPoint.h"

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

 @autoreleasepool {

           BLNPoint *p1 = [[BLNPoint alloc] init];      

           //向对象p1发送print消息       

           [p1 print];    

           //向对象p1发送moveToX: ToY:消息,该消息包含两个参数                           

           [p1 moveToX:100 ToY:200];

           //向类发送getOriginPoint消息

           [BLNPoint getOriginPoint];   

     }

     return 0;

}

上述例子中的-(void) print 方法是不带参数的,而-(void) moveToX:(int) x ToY:(int) y 函数是带有两个参数的方法,发送消息需要给参数赋值 [p1 moveToX:100 ToY:200]。如果方法有参数,方法名约定包含第一个参数名,如方法名moveToX:(int) x就包含了第一个参数,从第二个参数开始需要提供外部参数名 ,ToY:(int) y表示第二个参数,ToY是外部参数名。Objective-C中参数名是函数名的一部分,Objective-C不支持重载,如果两个函数名字相同,则出现错误。

上面两个方法都是实例方法,+(BLNPoint *) getOriginPoint是类型方法,只能通过向类发送该消息。Objective-C方法的定义以及调用/消息发送与C++的函数有较大差别,这里需要注意。

访问权限

Objective-C的实例方法可以访问的成员有:实例成员(属性,实例变量,实例方法)、类型方法、静态变量(实例方法我将其类比C++中class的普通成员函数,它可以访问所属类的所有成员)。

Objective-C的类型方法可以访问的成员有:类型方法,静态变量;不可以访问实例成员(类型方法将其类比为C++中静态成员函数,这种函数只能通过类名调用,并且函数内部只能访问静态变量,不能访问非静态变量)。

初始化器和析构器

  • 初始化对象实例时,使用alloc和init,如:BLNPoint *p1 = [[BLNPoint alloc] init],alloc分配内存,init初始化 。
  • 系统提供init方法,也可以自定义。如果要自定义初始化器,必须采用以下形式:

首先在类中声明:

@interface Book : NSObject

-(id) init;                  //默认初始化器

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

-(id) initWithName : (NSString *) name WithPage:(int) pages;     

-(id) initWithName : (NSString *) name WithPage:(int) pages WithCategory:(NSString *) category;

@end     

然后在implementation中定义初始化器:

#import "Book.h"

@implementation Book

-(id)init
{
    self = [super init];
    if(self)
        NSLog(@"Book Object init");
    return self;
}

-(id)initWithName:(NSString*)name
{
    return [self initWithName:name WithPages:0 WithCategory:@"General"];
}

-(id)initWithName:(NSString*)name WithPages:(int)pages
{
    return [self initWithName:name WithPages:pages WithCategory:@"General"];
}

//对参数最多的初始化器真正实现它,其他的初始化器则调用该函数

-(id)initWithName:(NSString*)name WithPages:(int)pages WithCategory:(NSString*)category
{
    self = [super init];

   //判断指针是否为nil,不是nil才能够初始化
    if(self)                                            
    {
        NSLog(@"Book Object init");
        _name = [name copy];               //对于指针变量要深拷贝
        _pages = pages;
        _category = [category copy];
    }
    return self;
}

自定义初始化器的格式通常如下:调用父类的初始化器--初始化实例变量,即用传入参数赋值实例变量,对于指针变量必须调用copy方法(copy方法类似于C++类中的深拷贝,既拷贝了指针,又拷贝了相应的内存,并让拷贝指针指向拷贝内存)。如果不调用copy方法,那么当传入变量变化时,类中相应实例变量也会发生变化,这不是我们希望发生的现象。

当有多个初始化器,每个初始化器参数个数不同时,通常真正实现参数最多的初始化器,其他的初始化器则可以直接调用该初始化器。

  • 类初始化器initialize:负责类型级别的初始化,initialize在每个类使用之前被系统自动调用,子类的initialize会自动调用initialize。类初始化器一般不需要自定义。
  • 对象析构器dealloc:由系统自动释放ARC管理的资源,需要手动释放不受ARC管理的动态内存:如malloc分配的内存,以及非内存资源:如文件句柄,网络端口。

3.字符串NSString

(1)字符串NSString

初始化

字符串的初始化方法有:直接初始化,初始化器,工厂方法。例如:

  //直接初始化

NSString *str1 = @"Hello World!";    

  //初始化器                                                                                             

NSString *str2 = [[NSString alloc] initWith:"Hello World!" encoding:NSUTF8StringEncoding];  

//工厂方法 

NSString *str3 = [NSString stringWithCString:"Hello World" encoding:NSUTF8StringEncoding];   

常量性

字符串NSString恒定,不能更改。例如:

[str1 stringByAppendingString:@"Yes!"];                 

//错误,str依然是"Hello World!"

 如果要更改指针所指向的内容,需要重新返回新值,如下:

str1 = [str1 stringByAppendingString:@"Yes!"];        

//此时,指针str指向新的内容"Hello World!Yes!"

共享机制

NSString有共享机制,直接初始化的字符串,值相等的对象指向同一地址。

值相等和地址相等

if([str1 isEqualToString:str2])          

    //判断str1和str2值是否相等

if(str1==str2)                                      

  //判断str1和str2指向地址是否相等

NSMutableString

NSMutableString是NSString的子类,具有可变性,不具有共享机制。例如:

NSMutableString *mustr1 = [NSMutableString stringWithString:@"Hello World!"];

[mustr1 appendString:@"Mutable!"];          

//正确,此时mustr1为"Hello World!Mutable!"

3.集合Collection

集合类型主要有三种:NSArray、NSSet、NSDictionary,都具有常量性,它们都有可变子类:NSMutableArray、NSMutableSet、NSMutableDictionary。主要介绍数组NSArray,其余两种类型的使用基本类似。

NSArray

初始化

NSArray是一个类,初始化同样有三种方法:直接初始化,初始化器,工厂方法。例如:

NSArray *a1 = @[@"Shanghai",@"Beijing",@"New York",@"Paris"];                                                              

NSArray *a2 = [[NSArray alloc] initWithObjects:@"Shanghai",@"Beijing",@"New York",@"Paris",nil];    

NSArray *a3 = [NSArray arrayWithObjects:@"Shanghai",@"Beijing",@"New York",@"Paris",nil];               

其中使用初始化器和工厂方法初始化时必须用nil进行结束,nil不算在数组内。数组内元素必须是对象objects,即NSObjects的子类对象。如果是非对象类型,必须封装为对象。例如:

//基本数值类型变量,非对象

NSInteger number = 100;          

   //使用NSNumber封装为对象                 

NSNumber *numberObject1 = [NSNumber numberWithInteger: number];

  //使用@初始化数值对象     

NSNumber *numberObject2 = @300u;                                                                

Point point;        //结构类型  

point.h = 100;

point.v = 200;

 //使用NSValue封装为对象

NSValue *pointObject = [NSValue value:&point withObjectType:@encode(Point)];  

NSArray a4 = @[numberObject1,numberObject2,pointObject ];

常量性

NSArray具有常量性,不能更改元素长度和指针,但是指针指向的内容可以更改。根据常量性可知,对数组进行排序,要将排序结果赋给新NSArray。

遍历方法

数组的遍历有三种方式:快速枚举、迭代器模式、for循环。其中快速枚举方式速度快,最常用。

补充一个很重要的集合遍历方式:通过方法

        [arr enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) 

BLNPoint *p1 = [[BLNPoint alloc] initWithX:10 WithY:20];

BLNPoint *p2 = [[BLNPoint alloc] initWithX:20 WithY:40];

BLNPoint *p3 = [[BLNPoint alloc] initWithX:30 WithY:60];

BLNPoint *p4 = [[BLNPoint alloc] initWithX:40 WithY:80];

NSArray *a5 = @[p1,p2,p3,p4];

//快速枚举

for(BLNPoint *point in a5){};                  

//迭代器模式

NSEnumerator *enumerator = [a5 objectEnumerator];

BLNPoint *item;

while(item = [enumerator  nextObject]){};                

//for循环

for(int i=0;i<4;i++){};

数组查找

BLNPoint *target = [[BLNPoint alloc] initWithX:20 WithY:40];

NSUInteger index1 = [a5 indexOfObject:target];

NSUInteger index2 = [a5 indexOfObjectIdenticalTo:p3];

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值