对象(Class)的声明和定义

和其他的语言不同,OC的对象创建分为两个部分。声明部分(@interface)和实现部分(@implementation),且它们都必须使用@end结束。

对象的声明(OC中基本上所有的对象都继承自NSObject):

@interface Car : NSObject
{
int _wheels;
NSString *_color;
}
- (void)run;
+ (void)playMusic;
@end

对象的实现:

@implementation Car
-(void)run
{
NSLog(@"The %@ car that has %d wheels is running...", _color, _wheels);
}
+ (void)playMusic
{
NSLog(@"music palying...");
}
@end

@interface代码块的作用:

成员变量的声明和方法的声明。成员变量必须在花括号中声明。而方法则在花括号和@end之间声明

默认情况下成员变量的可访问性为protected。

@implementation代码块的作用:

用于方法的定义(实现)。以减号开头的方法属于实例方法,以加号开头的方法属于类方法。

@implementation部分同样可以声明成员变量,但是由于在多文件编译中.m文件不能被import,

所以在@implementation部分声明的变量总是私有的。

在实际开发中,@interface部分应该写在头文件中,实现部分则写在.m文件中。

实例化对象:

因为对象都继承自NSObject,所以我们可以使用new实例化对象。在OC中对象都是通过指针进行访问。

语法:

Car *car = [Car new];

实例化之后car变量就保存了Car对象的地址,通过这个地址我们就可以调用对象的方法。

方法调用:

     [car run];  // 实例方法调用 [对象名 方法名]
[Car playMusic]; // 类方法调用 [类名 方法名]

实例化对象的其他方法:使用alloc和init方法

在实际开发中很少像上面这样实例化变量,因为用这个方式初始化的对象功能太单一。new方法仅仅是把成员变量初始化为0。一般我们都会把变量的内存分配和初始化分开。

alloc方法是一个类方法,用于为变量分配内存空间。而init方法是一个实例方法,用于初始化成员变量。

知道这两个方法之后,我们就可以像下面这样实例化变量:

Car * car = [[Car alloc] init];

当然了,这样的作用和上面的[Car new]一样,因为new关键字只是包装了alloc和init的实现。

面向对象编程思想,覆盖并重写父类方法:

init方法实际上是一个构造方法. 既然OC可以重写父类方法,那么我们就可以通过重写init方法实现自己的初始化方式。如:

- (id)init
{
self = [super init];
if (self) {
_color = @"red";
_wheels = 4;
}
return self;
}

这种init语法是苹果官方给出的格式,先通过父类为我们完成一些必要的工作,父类成功返回后再实现我们自己的初始化方式。最后返回自己。self是OC中的关键字,是类内部的一个自我引用。类似java中的this关键字。

super是父类对象的一个引用, 基本上和java的super一样

除了重写父类的init方法之外,我们还可以定义自己的构造方法:

- (id)initWithWheels:(int)wheels andColor:(NSString *)color
{
self = [super init];
if (self) {
_wheels = wheels;
_color = color;
}
return self;
}

然后我们就可以这样调用方法:

Car *car = [[Car alloc] initWithWheels:8 andColor:@"green"];

上面的方法是一个带多个参数的方法,每个参数用冒号分开。多少个参数就有多少个冒号。参数之间的冒号必须至少留一个空格。第二个参数冒号前的andColor实际上只是一个增加代码可读性的描述信息,可以去掉。

如:

- (id)initWithWheels:(int)wheels :(NSString *)color   //wheels后面必须留一个空格,否则报错。
{
self = [super init];
if (self) {
_wheels = wheels;
_color = color;
}
return self;
}

然后方法就是这样调用:

Car *car = [[Car alloc] initWithWheels:8 :@"green"];  //同样,8后面必须留空格

这种代码可读性较差

 

面向对象编程思想,数据的封装

       我们都知道,把数据封装起来是为了防止对象内部的状态被意外修改,使我们的代码更加可靠。

OC可以通过这几个关键字控制成员变量的访问级别,@public, @protected, @private, @package

@public             公共访问级别,可以在对象外部任意访问,不建议使用

@protected       受保护的级别,只有本类和子类可访问。

@private           只有本类可以访问,子类可以通过父类的方法访问父类的私有变量

@package         只有同一个框架内部可以访问

默认情况下,OC中对象的成员变量是protected的,这样我们要访问受保护的变量就必须为变量提供访问方法(getter和setter)

现有一成员变量_wheels,那么根据OC的命名规范,变量_wheels的getter和setter就应该定义为:

-------------getter-----------------

- (int)wheels
{
return _wheels;
}

-------------setter------------------

- (void)setWheels:(int)wheels
{
_wheels = wheels;
}

然后我们就可以调用方法获取和设置变量的值

[car setWheels:12];  // 设置变量值
int count = [car wheels]; // 取得变量值

通过设置getter和setter访问成员变量的好处是我们可以控制变量的初始化。

如:

- (void)setWheels:(int)wheels
{
if (wheels < 0) {
wheels = 4;
}
_wheels = wheels;
}

这样我们就可以防止一辆没有车轮的汽车出现在我们的视线。

 

OC中的点语法

在其他支持点语法的语言中,可以直接通过点语法访问成员中的变量。但是在OC中的点语法则不是。

假设person类中有一个公共成员变量_name,我想这样访问这个变量 person._name,是不行的。

要OC支持点语法,我们必须提供要访问的变量的getter和setter。

在上面Car对象中我们已经设置了_wheels变量的getter和setter,那么我们就可以使用点语法了:

Car *car = [[Car alloc] init];
car.wheels = 4; //设置变量值,相当于调用[car setWheels:4];
NSLog(@"%d wheels", car.wheels); //获取变量值,相当于调用[car wheels];

点语法实际上是通过调用变量的getter和setter方法访问成员变量,

如果编译器发现当前语句是一个赋值语句,就调用setter,如果是取值语句,则调用getter。

 

在OC中使用属性(@property和@synthesize)

概念:property能够简化类成员变量的定义,如果需要,能够自动为类生成getter和setter,在旧版本的xcode,必须同时使用@property和@synthesize。

再来看前面的Car类

声明:

#import <Foundation/Foundation.h>
@interface Car : NSObject
{
int _wheels;
NSString *_color;
}
- (void)run;
+ (void)playMusic;
- (id)init;
- (id) initWithWheels:(int)wheels :(NSString *)color;
- (void)setWheels:(int)wheels;
- (int)wheels;
- (void)setColor:(NSString *)color;
- (NSString *)color;
@end

实现:

#import "Car.h"
@implementation Car -(void)run
{
NSLog(@"The %@ car that has %d wheels is running...", _color, _wheels);
}
+ (void)playMusic
{
NSLog(@"music palying...");
}
- (id)init{
self = [super init];
if (self) {
_color = @"red";
_wheels = 4;
}
return self;
}
- (id)initWithWheels:(int)wheels :(NSString *)color
{
self = [super init];
if (self) {
_wheels = wheels;
_color = color;
} return self;
}
- (void)setWheels:(int)wheels
{
if (wheels < 0) {
wheels = 4;
}
_wheels = wheels;
}
- (int)wheels{
return _wheels;
}
- (void)setColor:(NSString *)color
{
_color = color;
}
- (NSString *)color
{
return _color;
}
@end

现在我们使用@property来重写

声明:

#import <Foundation/Foundation.h>
@interface Car : NSObject
{
int _wheels;
NSString *_color;
}
@property int wheels;
@property NSString *color;
- (void)run;
+ (void)playMusic;
- (id)init;
- (id) initWithWheels:(int)wheels :(NSString *)color;
@end

实现:

#import "Car.h"@implementation Car
@synthesize wheels = _wheels;
@synthesize color = _color;
-(void)run
{
NSLog(@"The %@ car that has %d wheels is running...", _color, _wheels);
}
+ (void)playMusic
{
NSLog(@"music palying...");
}
- (id)init
{
self = [super init];
if (self) {
_color = @"red";
_wheels = 4;
} return self;
}
- (id)initWithWheels:(int)wheels :(NSString *)color
{
self = [super init];
if (self) {
_wheels = wheels;
_color = color;
}
return self;
}
@end

重写后getter和setter方法都可以删除,@property关键字可以帮我们自动生成getter和setter的声明。

而@synthesize则生成getter和setter的实现。

@synthesize解析:@synthesize wheels = _wheels 和 @synthesize wheels 的区别

当使用前者,我们指定setter和getter访问名为_wheels的变量,而后者的getter和setter方法则访问名为wheels的变量。

那么 @synthesize wheels = _wheels 生成的方法为:

- (void)setWheels:(int)wheels
{
_wheels = wheels;
}
- (int)getWheels
{
return _wheels;
}

而@synthesize wheels则是:

- (void)setWheels:(int)wheels
{
wheels = wheels;
}
- (int)getWheels
{
return wheels;
}

在新版本的xcode中,@property完全兼顾了@synthesize的作用,包含了声明和实现。

因此,在高版本的xcode中,只需要使用@property就可以生成get,set的声明和实现。

而且@property还帮我们自动生成相应的成员变量。

下面的Person类只定义了两个property,但是已经自动生成了get,set方法和_age, _name 成员变量:

声明:

#import <Foundation/Foundation.h>
@interface Person : NSObject
@property int age;
@property NSString *name;
@end

实现:

#import "Person.h"
@implementation Person
@end

 

扩展类方法:使用category

category可以不用修改源代码文件扩展原有类的方法。

语法:

声明部分:

@interface NSString (Hello)
+ (void)sayHello;
@end

@interface后面跟的是我们想扩展哪一个类,括号中的hello是一个描述,该名字最好能描述我们扩展的方法的功能。

实现部分:

@implementation NSString (Hello)
+ (void)sayHello{
NSLog(@"hello world");
}
@end

完成之后我们就为NSString类添加了一个sayHello方法,这个方法是一个类方法,因为它前面的是+符号。

可以这样调用这个方法: [NSString sayHello];

当扩展的方法和已有的方法冲突,category方法优先调用。

 

使用协议 protocol

OC中的协议类似java中的接口,与java接口不同的是,协议中的方法可以并不一定都要实现。

使用@optional关键字可以声明可选的方法。如果类实现了协议中的方法,我们说该类遵守(conform to)了这个协议

语法:尖括号里面的就是我们遵从的协议

#import <Foundation/Foundation.h>
@protocol TestProtocol <NSObject>
@required
+(void)test;
@optional
+(void)test2;
@end

上面的代码建立了一个TestProtocol的协议,协议里面声明了test方法。遵从这个协议就要实现这个方法。

但是test2方法则是可选的。TestProtocol协议本身遵从了NSObject协议。

OC中的block语法

block可以用来包含一组代码块,它与函数有一定的相似性。block语法使用" ^ "符号为前缀。

定义一个简单的block:

^{
NSLog(@"hello world");
}();

上面的代码定义一个块并运行该块。在旧版本xcode中也许你会见到下面的代码:

^{
NSLog(@"hello world");
}

但是在新版本的xcode中这样的代码已经出错:

如果你选择在block后面添加分号,错误是消失了,但是这个快你永远也无法调用,因为它没有名字。

block是一种类型,因此可以这样定义这种类型:

void(^simpleBlock)() = ^(){
NSLog(@"this is a simple block");
};

block的调用:

simpleBlock();

可见block的使用和函数非常相似。

block还可以有参数和返回值:

int(^sum)(int, int) = ^(int i, int j){
return i+j;
}; int total = sum(10, 20); //total的值为30

默认情况下在block里面访问外面的变量是只读的

int main(int argc, const char * argv[]) {
int i = 20;
^(void){
NSLog(@"%d", i);
}(); return 0;
}

如果想修改块外边的变量,该变量就要使用__block关键字修饰:

int main(int argc, const char * argv[]) {
__block int i = 20;
^(void){
i = i+1;
NSLog(@"%d", i);
}(); return 0;
}

block块还经常作为参数传递。

Objective-c快速入门的更多相关文章

  1. Objective C 快速入门学习一

    Objective-C程序设计 1. 直接用Xcode作为IDE,舍弃gcc编译方面的学习.2. 入门例子:Eg:打印Hello World 控制台程序 #import<Foundation/F ...

  2. Objective C 快速入门学习五

    <一>继承和多态 @class Complex 声明类(同C++) 子类函数成员 super 访问父类 同C++类似 .通过继承 在子类中添加新方法 .通过继承 在子类中添加新成员 .通过 ...

  3. Objective C 快速入门学习四

    类 1.合成存取器方法 @property   成员变量 @synthesize 成员变量 可以让编译器自动合成 设置和获取函数的方法,不用手动生成set成员变量,Get成员变量 @interface ...

  4. Objective C 快速入门学习三

    1.数据类型 和C语言基本一样. 有一个特别数据类型id,可以储存任何类型的对象,它是实现多态和动态绑定的基础. Objective-C 2.程序结构 Objective-C和C的程序结构一模一样,具 ...

  5. Objective C 快速入门学习二

    Objective-C 类.对象.方法 1.编写一个复数类: #import <Foundation/Foundation.h>@interface Complex: NSObject / ...

  6. Web Api 入门实战 (快速入门+工具使用+不依赖IIS)

    平台之大势何人能挡? 带着你的Net飞奔吧!:http://www.cnblogs.com/dunitian/p/4822808.html 屁话我也就不多说了,什么简介的也省了,直接简单概括+demo ...

  7. SignalR快速入门 ~ 仿QQ即时聊天,消息推送,单聊,群聊,多群公聊(基础=》提升)

     SignalR快速入门 ~ 仿QQ即时聊天,消息推送,单聊,群聊,多群公聊(基础=>提升,5个Demo贯彻全篇,感兴趣的玩才是真的学) 官方demo:http://www.asp.net/si ...

  8. 前端开发小白必学技能—非关系数据库又像关系数据库的MongoDB快速入门命令(2)

    今天给大家道个歉,没有及时更新MongoDB快速入门的下篇,最近有点小忙,在此向博友们致歉.下面我将简单地说一下mongdb的一些基本命令以及我们日常开发过程中的一些问题.mongodb可以为我们提供 ...

  9. 【第三篇】ASP.NET MVC快速入门之安全策略(MVC5+EF6)

    目录 [第一篇]ASP.NET MVC快速入门之数据库操作(MVC5+EF6) [第二篇]ASP.NET MVC快速入门之数据注解(MVC5+EF6) [第三篇]ASP.NET MVC快速入门之安全策 ...

  10. 【番外篇】ASP.NET MVC快速入门之免费jQuery控件库(MVC5+EF6)

    目录 [第一篇]ASP.NET MVC快速入门之数据库操作(MVC5+EF6) [第二篇]ASP.NET MVC快速入门之数据注解(MVC5+EF6) [第三篇]ASP.NET MVC快速入门之安全策 ...

随机推荐

  1. Windows 10 安装 Sql Server 2014 反复提示需要安装 .NET Framework 3.5 SP1 的解决方案

    一.首先安装.NET Framework 3.5: 离线安装方式: 1.装载相对应的系统安装盘,我是Windows 10 x64 企业版,所以装载Windows 10 x64 企业版安装镜像ISO,盘 ...

  2. 【手记】调用Process.EnterDebugMode引发异常:并非所有引用的特权或组都分配给呼叫方

    刚上线一个新版本,其中有台电脑打开软件就报[xx的类型初始值设定项引发异常](还好不是一大波电脑,新东西上线就怕哀鸿遍野),如图: 显然是该类型的静态构造函数中抛异常了(红线处就是类名),遂打开该类, ...

  3. 安装MySql for Visual Studio的坑

    阅读目录 问题描述 解决过程 解决方案 总结 回到顶部 问题描述 安装MySql for Visual Studio 一般来说是为了能在VS的服务器数据连接的数据源中能选择MySql类型,如下图: 但 ...

  4. VMware12下安装Debian8.5

    参考:  Debian 8.2.0 (Jessie) 快速纯净安装教程    Debian 7 安装配置总结    Debian 7.8 系统安装配置过程 软件包管理命令    包命令    从源代码 ...

  5. 如何实现一个php框架系列文章【6】mysql数据库

    实现一个mysql数据库封装需要考虑的问题 使用方便性 采用直接sql语句操作方式.只要会写sql语句,那么将没有其他学习成本. uctphp框架提供的dba辅助封装类,用会之后将爱不释手. 使用前需 ...

  6. Spring boot: Request method 'DELETE' not supported, Request method 'PUT' not supported, Request method 'POST' not supported

    GET,POST,PUT,DELETE, Spring都支持,不要怀疑Spring, 一定是前端发送的rest 请求和后端的响应不匹配, 查找原因以及解决办法, 很简单 用chrome打开F12控制台 ...

  7. 一些简单的C语言算法

    1. 要求输入一个正整数,打印下述图形 输入:5 输出: * ** *** **** ***** 实现代码如下: #include <stdio.h> int main(int argc, ...

  8. Lind.DDD.SSO单点登陆组件的使用(原创)

    回到目录 一般sso的说明 在Lind.DDD框架里,有对单点登陆的集成,原理就是各个网站去sso网站统一登陆授权,之后在sso网站将登陆的token进行存储,存储方式随你(cache,redis,m ...

  9. java 正则匹配括号对以及其他成对出现的模式

    最近,我们有个大调整,为了控制代码的质量,需要使用一些伪代码让业务人员编写应用逻辑(其实这么做完全是处于研发效能的考虑,95%以上的代码不需要特别注意都不会导致系统性风险,),然后通过工具自动生成实际 ...

  10. cookie存储对象信息

    最近看到某公司某项目中用于保存多个城市信息到cookie中的方法,该方法的逻辑是按时间顺序记录最近访问过的三个城市的名字及id,逻辑包插入与含排重.插入与排重的代码如下: 1 2 3 4 5 6 7 ...