Objective-C 30分钟入门教程

我第一次看OC觉得这个语言的语法有些怪异,为什么充满了@符号,[]符号,函数调用没有()这个,但是面向对象的高级语言也不外乎类,接口,多态,封装,继承等概念。下面会把OC里面的一些定义与Java,C++作对比,让有其他面向对象语言的同学可以快速的了解OC是个神马语言。

1.类定义

类用@interface定义,而不是@class,相当于Java中的class了。而Object-C中接口(Java中的接口)是用@protocol(下面有介绍)表示。

头文件,与c++的头文件类似

 #import <Foundation/Foundation.h>
@interface Fraction : NSObject
//成员变量
{
@protected
int numerator;
int denominator;
}
//类方法
-(void) print;
//多参数函数
-(id)initSetNum:(int) n over:(int) d;
-(id) init;
@end

实现.m文件(相当于c中的.cpp)

 #import "Fraction.h"

 @implementation Fraction

 -(void) print {
NSLog(@"print");
} -(id)init{
self = [super init];
if (self != nil) {
self->denominator = ;
self->numerator = ;
}
return self;
}
-(void)set:(int)n over:(int)d {
self->denominator = d;
self->numerator = n;
} @end

init模板

 -(id)init{
self = [super init];
if (self) {
//do init
}
return self;
}

2.访问权限

实例变量的作用域

  • @protected: 实例变量可被该类和子类中定义的方法直接访问。接口部分定义的实例变量是此作用域
  • @private: 只能被定义在此类中的方法直接访问。定义在实现部分的实例变量默认为此作用域
  • @public: 可被此类中的方法、子类或其他类直接方法(访问方法见下面点语法
  • @package: 对于64位镜像,可以在实现改类的镜像中的任何地方访问此实例变量(不了解,没用过

@property作用域

@property只在@interface中使用,是默认的@protected权限

方法的作用域

@protected,@private,@public,@package不适用实例方法,在@interface中定义的方法都是@public方法

私有方法

1.不在@interface中声明,直接写到@implemention里。
2.写在空分类中

3.@property和@synthesize

语法

@property(attribute1, attribute2, ...) type name;

作用1:生成成员变量的get和set方法
 @interface Fraction : NSObject
@property int numerator, denominator;
-(void)print;
@end
 @implementation Fraction
@synthesize numerator = _abc, denominator = _def; -(void) print {
self->_abc = ;
self->_def = ;
}
@end
 #import <Foundation/Foundation.h>
#import "Fraction.h" int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
Fraction * fraction = [[Fraction alloc]init];
[fraction setNumerator:];
NSLog(@"numerator is %d", [fraction numerator]); fraction.numerator = ;
NSLog(@"numerator is %d", fraction.numerator);
}
return ;
}

@property int numerator, denominator;

@synthesize numerator = _abc, denominator = _def;

两句话为我们生成了(暂时不考虑内存管理)

 (void) setNumerator:(int) n {
//@synthesize numerator, denominator; 若是这样则
//self->numerator = n;
self->_abc = n;
} (void) setDenominator:(int) n {
self->_def = n;
} (int) numerator {
return self->_abc;
} (int) denominator {
return self->_abc;
}
如果不写@synthesize,编译器会自动生成@ synthesize name = _name

若写@synthesize name,则相当于写了@synthesize name = name

点语法

oc的点语法比较特殊,c++或java定义一个实例变量,则可以this->num或instance.num就可以取得次变量了,但是oc不行!点相当于调用set和get方法,并且oc中的实例方法调用也不能用点(get set不算),比如instance.print()是不行的,要[instance print]才行

作用2:协助内存管理

attribute主要分三类:

  • 读写属性:(readwrite/readonly)决定是否生成set访问器,默认为readwrite
  • setter语义:(assign/retain/copy/strong/weak/unsafe_unretained)set访问器的语义,决定已何种方式对数据成员赋予新值,默认为assign
  • 原子性:(atomic/nonatomic)是否是原子性访问,默认为nonatomic

readwrite: 生成setter/gettter方法(默认)

readonly: 只生成getter。@synthesize不会生成setter方法,所以不能和copy/retain/assign同时使用

assign: 简单赋值,不更改索引计数

retain: 释放旧的对象,将旧对象的值赋予输入对象,在增加输入对象的引用计数(+1)。此属性只能用于Objective-c对象类型,不能用于基本类型和Core Foundation对象(Core Foundation?此乃何物),因为他们没有引用计数

strong/weak/unsafe_unretained: xcode5加入的新属性,strong = retain,unsafe_unretained = assign,weak ~= assign,在引用计数为0时,对吧对象赋值为nil

copy: 建立一个引用计数为1的对象,然后释放旧对象。此属性只对实现了NSCopying的对象类型有效

atomic/nonatomic: setter和getter是不是原子操作,如果是atomic则在多线程情况下,setter和getter中不会被阻塞(切换线程)

4.分类(category)、扩展(extension)和协议(protocol)

分类

这个概念在c++和java我找不到对应的概念,算是oc特性了

在一个类已经定义好了的情况下,又想向类中增加一些新方法,但是有不想改原来的实现文件,或是找不到实现文件,这就是分类发挥作用的时候了,比如想在Fraction类中增加-(void)double方法,用分类可以这么搞

MathOps.h文件

 #import "Fraction.h"
@interface Fraction(MathOps)
-(void)double;
@end

MathOps.m文件

 #import "Fraction.h"
@implementation Fraction(MathOps)
-(void)double {
[self numerator] = [self numerator] * ;
}
@end

这样就可以在Fraction的实例上使用[fraction double];了

类实例变量的扩展(extension)

类扩展(extension)是category的一个特例,有时候也被称为匿名分类。他的作用是为一个类添加一些私有的成员变量和方法。

类实例的扩展只能在未命名分类中定义,在命名分类中是不允许的,并且要写在响应的.m文件中

 #import "Fraction.h"
@interface Fraction() //括号里是空就是了
{
int MaxNum;
} @property int minNum; @end

Objective-C第229页说,未命名分类是非常有用的,因为他们的方法都是私有的,如果要谢一个类,而且数据和方法仅供这个类本身使用,未命名分类比较合适,但是使用@selector依然可以访问,例如[A performSelector: @selector(privateTest)];

协议@protocol

协议有点像java中的接口,只提供方法的声明,实现由使用此协议的类来实现

 @protocol NSCopying
-(id)copyWithZone:(NSZone *)zone;
@end

采用协议的类用<protocolName1,protocolName,...>来声明采用了protocolName协议

@interface className: NSObject

协议中的方法类中不用全部实现,@optional后的方法不一定要实现,@required或默认的方法一定要实现

 @protocol Drawing
-(void)paint; //采用的类中必须实现
-(void)erase; //采用的类中必须实现
@optional
-(void)outline; //采用的类中不一定实现
@required
-(void)showDetail; //采用的类中必须实现
@end

可以在声明对象时候指明它采用的协议,这样在赋值时由编译器检查被复制对象是否采用了协议,若没有则发出警告

id<Drawing> currentOBject;

协议自身也可以扩展其他的协议 @protocol Drawing3D<Drawing>

分类也可以采用协议 @interface Fraction(Stuff)这是啥??

5.Foundation框架

Foundation框架,Application Kit框架,Cocoa

框架是由许多类、方法、函数和文档按照一定的逻辑组合起来的集合,在Mac OS X系统下大约有90多个框架。

为所有的程序开发奠定基础的框架称为Foundation框架,它允许使用一些结拜的对象,如数字和字符串,一些对象集合,如数字、字典和集合。其他功能包括处理日期和时间、自动化的内存管理、文件系统等。

Application Kit框架包含广泛的类和方法,它们用来开发交互式的图形应用程序,使得开发文本、菜单、工具栏、表、窗口之类的过程变得十分简便(Application Kit开发Mac app,UIKit开发手持IOS ap)。术语Cocoa Touch是指Foundation、Core Data和UIKit框架。术语Cocoa是指Foundation、Core Data、Application Kit框架。

  • NSNumber: 把int、float、char等基本类型搞成对象,以便可以放到NSArray等必须存储对象的容器。
  • NSString/NSMutableString: 字符串类,一个不可变,一个可变
  • NSArray/NSMutableArray: 数组类,一个不可变,一个可变
 NSArray * name = [NSArray arrayWithObjects:@"zhangsan", @"lisi", @"dawang", nil];

 NSMutableArray * nameMutable = [NSMutableArray array];
for (int i = ; i < ; i++) {
nameMutable = [NSNumber numberWithInteger: i];
}
  • NSValue: 把Foundation集合中的非对象(int、float等用NSNumber)比如C中结构体CGPoint包装(wrapping)成对象,使用时再把对象展开(unwrapping)得到CGPoint。
 CGPonit myPonit;
NSValue * ponitObj;
NSMutableArray * touchPoints = [NSMutableArray array]; myPonit.x = ;
myPoint.y = ; pointObj = [NSValue valueWithPoint:myPint];
[touchPoints addObject: pointObj]; myPoint = [[touchPoints lastObject]pointValue];
  • NSDictionary/NSMutableDictionary: 字典,keyValue结构
 NSMutableDictionary * glossary = [NSMutableDictionary dictionary];

 [glossary setObject:@"zhangSan" forKey:@"zhang"];
[glossary setObject:@"zhaoSi" forKey:@"zhao"]; NSLog(@"name zhang is: %@", [glossary objectForKey:@"zhang"]); NSDictionary * glossaryDic =
[NSDictionary dictionaryWithObjectsAndKeys:
@"zhangSan", @"zhang",
@"zhaoSi", @"zhao",
nil]; for (NSString * key in glossaryDic) {
NSLog(@"%@:%@", key, [glossary objectForKey: key]);
}
  • NSSet/NSMutableSet/NSIndexSet: 集合类,可用的操作包括搜索、添加、删除、比较、计算交集、计算并集等操作。

6.ARC内存管理

ARC(Automatic Reference Counting)自动引用计数(神马是引用计数自行脑补)。Xcode 4.2版本之后加入的新特性。Xcode4.2之前的内存管理要内存要小心的处理引用计数,retain,release,autorelease在代码中随处可见。

XCode4.2之后的ARC是在编译的时候由编译器在代码中添加retain,release,autorelease代码,程序要要做的就是开启ARC(默认开启)功能,在@property属性参数中声明号strong,weak等属性就行了(定义变量时也可以用strong,weak等)。开启ARC后不能使用retain,release,编译不通过。

@autorealeasepool

任何在@autoreleasepool{}中定义的变量都是autorelease的,在出@autoreleasepool{}作用域时,会对其中的变量做一次release操作。

Cocoa和IOS应用程序中也有这个@autoreleasepool{},也就是说Cocoa和IOS中的变量都是autorelease的,每帧循环后会对autoreleasepool中的对象做一次pop操作,把对象从autoreleasepool中删除,并做一次release。Objective-C Autorelease Pool 的实现原理这个介绍了ios中的autorealeasepool

7.杂项

NSLog(@"%@", object)

NSLog添加了%@这么一个输出格式,%@对应的对象在编译后会被替换为对descriptionWithLocal方法的调用,如果此方法不存在,则替换为description方法的调用 。

8.selector

SEL 类成员方法的指针

可以理解 @selector()就是取类方法的编号,他的行为基本可以等同C语言的中函数指针,只不过C语言中,可以把函数名直接赋给一个函数指针,而Object-C的类不能直接应用函数指针,这样只能做一个@selector语法来取.

它的结果是一个SEL类型。这个类型本质是类方法的编号(函数地址)

C/C++函数指针

int test(int val)

{
return val+1;

}

int (* c_func)(int val); //定义一个函数指针变量c_func = add ; //把函数addr地址直接赋给c_func

object-c的选择器,

@interface foo
-(int)add:int val;

@end

SEL class_func ; //定义一个类方法指针class_func = @selector(add:int);

注意1、@selector是查找当前类(含子类)的方法。

举例:

父类.h文件

 #import <Foundation/Foundation.h>  

 @interface SelectorDemo : NSObject
{
SEL _methodTest;
} @property (nonatomic,assign) SEL methodTest;//这里声明为属性方便在于外部传入。 -(void)TestParentMethod; -(void)TestSubMethod; @end

.m文件

 #import "SelectorDemo.h"  

 @implementation SelectorDemo  

 @synthesize methodTest = _methodTest;  

 -(void)parentMethod
{
NSLog(@"parent method Call Success!");
} -(void)TestParentMethod
{
if (_methodTest)
{
[self performSelector:_methodTest withObject:nil];
}
} -(void)TestSubMethod
{
if (_methodTest)
{
[self performSelector:_methodTest withObject:nil];
}
} @end

子类.h文件

 #import <Foundation/Foundation.h>
#import "SelectorDemo.h" @interface SelectorSub : SelectorDemo @end

.m文件

#import "SelectorSub.h"  

@implementation SelectorSub  

-(void)SubMethod
{
NSLog(@"Sub method Call Success!");
} @end

进行测试调用。

SelectorSub *ss = [[SelectorSub alloc]init];
ss.methodTest = @selector(parentMethod);
[ss TestParentMethod];
ss.methodTest = @selector(SubMethod);
[ss TestParentMethod];
[ss release];

ss.methodTest = @selector(parentMethod); 这句在运行期时,会寻找到父类中的方法进行调用。

ss.methodTest = @selector(SubMethod);//这句就在运行期时,会先寻找父类,如果父类没有,则寻找子类。

如果这里将ss.methodTest = @selector(test); 其中test即不是ss父类,也不是ss本身,也非SS子类,哪么这个时候在使用

[self performSelector:_methodTest withObject:nil];就会出现地址寻找出错 。

[friend performSelector:@selector(gossipAbout:) withObject:aNeighbor];

等价于:

[friend gossipAbout:aNeighbor]; 

通过这个原理,当把属性设置为SEL类型时,如果回调机制使用的不是SEL声明的类或子类。想实现其它类的回调,必须传入其它类的上下文句柄。

#import <Foundation/Foundation.h>  

@interface SelectorDemo : NSObject
{
SEL _methodTest;
id _handle;
} @property (nonatomic,assign) SEL methodTest;
@property (nonatomic,retain) id handle; //添加其它类的实例句柄属性。
-(void)TestParentMethod;
-(void)TestSubMethod; @end
#import "SelectorDemo.h"  

@implementation SelectorDemo  

@synthesize methodTest = _methodTest;
@synthesize handle = _handle; -(void)parentMethod
{
NSLog(@"parent method Call Success!");
} -(void)TestParentMethod
{
if (_methodTest)
{
[_handle performSelector:_methodTest withObject:nil];//这里面原来self属为相应的实例句柄
}
} -(void)TestSubMethod
{
if (_methodTest)
{
[_handle performSelector:_methodTest withObject:nil];
}
} @end

便可如此调用

C * c = [[SubS alloc]init];

c.methodTest = @selector(Show);
c.handle = [[AnotherC alloc]init]; [c handleTest]; 

9.Block

有参数有返回值的demo

 - (void)myThirdBlock
{
//1.定义block
double (^myThirdBlock)(double,double) = ^ (double r1,double r2){
return r1 + r2;
};
//2.调用block
double r3 = myThirdBlock(1.1,2.2);
NSLog(@"有参数有返回值:%f",r3);
}

block的注意点

1)Block内部可以访问外部变量;

2)默认情况下,Block内部不能修改外部的局部变量

3)给局部变量加上__block关键字,则这个局部变量可以在block内部进行修改

示例代码如下:

 - (void)myFourBlock
{
int num = ;
void (^myFourBlock)() = ^{ num = ;
NSLog(@"%d",num);
};
}

//发现需要的再加

结语

本博介绍了OC的核(pi)心(mao)概念,希望看完本博可以对让你对OC有一个大体的认识,学OC是学ios的第一步, 打下坚实的OC还是很必要的。

参考

Objective-C 30分钟入门教程的更多相关文章

  1. 正则表达式30分钟入门教程<转载>

    来园子之前写的一篇正则表达式教程,部分翻译自codeproject的The 30 Minute Regex Tutorial. 由于评论里有过长的URL,所以本页排版比较混乱,推荐你到原处查看,看完了 ...

  2. PHP正则表达式30分钟入门教程

    正则表达式30分钟入门教程 三个常用的知识点: 1.惰性匹配:正则引擎默认是贪婪的,若要最少重复的话,需要用到惰性匹配符 “?” 懒惰限定符 代码/语法 说明 *? 重复任意次,但尽可能少重复 +? ...

  3. HTML 30分钟入门教程

    作者:deerchao 转载请注明来源 本文目标 30分钟内让你明白HTML是什么,并对它有一些基本的了解.一旦入门后,你可以从网上找到更多更详细的资料来继续学习. 什么是HTML HTML是英文Hy ...

  4. js正则表达式30分钟入门教程

    2011-10-27 13:23:15 如何使用本教程 最重要的是——请给我30分钟,如果你没有使用正则表达式的经验,请不要试图在30秒内入门——除非你是超人 :) 别被下面那些复杂的表达式吓倒,只要 ...

  5. Python 30分钟入门指南

    Python 30分钟入门指南 为什么 OIer 要学 Python? Python 语言特性简洁明了,使用 Python 写测试数据生成器和对拍器,比编写 C++ 事半功倍. Python 学习成本 ...

  6. Shell脚本编程30分钟入门

    Shell脚本编程30分钟入门 转载地址: Shell脚本编程30分钟入门 什么是Shell脚本 示例 看个例子吧: #!/bin/sh cd ~ mkdir shell_tut cd shell_t ...

  7. 30分钟入门Java8之方法引用

    30分钟入门Java8之方法引用 前言 之前两篇文章分别介绍了Java8的lambda表达式和默认方法和静态接口方法.今天我们继续学习Java8的新语言特性--方法引用(Method Referenc ...

  8. 30分钟入门Java8之默认方法和静态接口方法

    30分钟入门Java8之默认方法和静态接口方法 前言 上一篇文章30分钟入门Java8之lambda表达式,我们学习了lambda表达式.现在继续Java8新语言特性的学习,今天,我们要学习的是默认方 ...

  9. 【原创】30分钟入门 github

    很久没更新了,这篇文章重点在github的入门使用,读者可以下载github for windows shell,边看边操作,加深印象. 好了,30分钟的愉快之旅开始吧: 一.github使用的注意事 ...

随机推荐

  1. 远程管理 KVM 虚机 - 每天5分钟玩转 OpenStack(5)

    上一节我们通过 virt-manager 在本地主机上创建并管理 KVM 虚机.其实 virt-manager 也可以管理其他宿主机上的虚机.只需要简单的将宿主机添加进来 填入宿主机的相关信息,确定即 ...

  2. MySQL学习笔记十六:锁机制

    1.数据库锁就是为了保证数据库数据的一致性在一个共享资源被并发访问时使得数据访问顺序化的机制.MySQL数据库的锁机制比较独特,支持不同的存储引擎使用不同的锁机制. 2.MySQL使用了三种类型的锁机 ...

  3. MVC, MVP, MVVM比较以及区别(上)

    MVC, MVP和MVVM都是用来解决界面呈现和逻辑代码分离而出现的模式.以前只是对它们有部分的了解,没有深入的研究过,对于一些里面的概念和区别也是一知半解.现在一边查资料,并结合自己的理解,来谈一下 ...

  4. C语言 第八章 函数、指针与宏

    一.函数 函数是一个包含完成一定功能的执行代码段.我们可以把函数看成一个"黑盒子", 你只要将数据送进去就能得到结果, 而函数内部究竟是如何工作的的, 外部程序是不知道的.外部程序 ...

  5. DEBIAN下中文显示

    转:http://www.cppblog.com/colorful/archive/2012/05/28/176516.aspx 一.首先检查LOCALE情况 说明:DEBIAN因为基于GNU所以,对 ...

  6. ListView中的数据表格写入Excel中

    SaveFileDialog sfd = new SaveFileDialog(); sfd.DefaultExt = "xls"; sfd.Filter = "Exce ...

  7. Androide SQLiteDatabase数据库操作(转)

    SQLite可以解析大部分的标准SQL语句:建表语句:create table 表名(主键名 integer primary key autoincrement(设置为自增列),其他列名及属性)或(主 ...

  8. Windows Phone 8 开发系列(持续更新中)

    1. 从应用列表再次点击应用,如何恢复到上次浏览的页面呢? 2. Windows Phone 文本框的 UpdateSourceTrigger 属性不支持 PropertyChanged 怎么办? 3 ...

  9. Hibernate —— 映射关联关系(附录)

    一.单向的多对一 1.建表语句 CREATE TABLE customer ( customer_id ) NOT NULL AUTO_INCREMENT PRIMARY KEY , ) CREATE ...

  10. jquery的事件命名空间详解

    jquery现在的事件API:on,off,trigger支持带命名空间的事件,当事件有了命名空间,就可以有效地管理同一事件的不同监听器,在定义组件的时候,能够避免同一元素应用到不同组件时,同一事件类 ...