zoukankan      html  css  js  c++  java
  • Objective-C 30分钟入门教程

    Objective-C 30分钟入门教程

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

    1.类定义

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

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

     1 #import <Foundation/Foundation.h>
     2 @interface Fraction : NSObject
     3 //成员变量
     4 {
     5 @protected
     6     int numerator;
     7     int denominator;
     8 }
     9 //类方法
    10 -(void) print;
    11 //多参数函数
    12 -(id)initSetNum:(int) n over:(int) d;
    13 -(id) init;
    14 @end

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

     1 #import "Fraction.h"
     2 
     3 @implementation Fraction
     4 
     5 -(void) print {
     6     NSLog(@"print");
     7 }
     8 
     9 -(id)init{
    10     self = [super init];
    11     if (self != nil) {
    12         self->denominator = 1;
    13         self->numerator = 1;
    14     }
    15     return self;
    16 }
    17 -(void)set:(int)n over:(int)d {
    18     self->denominator = d;
    19     self->numerator = n;
    20 }
    21 
    22 @end

    init模板

    1 -(id)init{
    2     self = [super init];
    3     if (self) {
    4         //do init 
    5     }
    6     return self;
    7 }

    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方法
    1 @interface Fraction : NSObject
    2 @property int numerator, denominator;
    3 -(void)print;
    4 @end
    1 @implementation Fraction
    2 @synthesize numerator = _abc, denominator = _def;
    3 
    4 -(void) print {
    5     self->_abc = 12;
    6     self->_def = 30;
    7 }
    8 @end
     1 #import <Foundation/Foundation.h>
     2 #import "Fraction.h"
     3 
     4 int main(int argc, const char * argv[]) {
     5     @autoreleasepool {
     6         // insert code here...
     7         Fraction * fraction = [[Fraction alloc]init];
     8         [fraction setNumerator:10];
     9         NSLog(@"numerator is %d", [fraction numerator]);
    10         
    11         fraction.numerator = 20;
    12         NSLog(@"numerator is %d", fraction.numerator);
    13     }
    14     return 0;
    15 }

    @property int numerator, denominator;

    @synthesize numerator = _abc, denominator = _def;

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

     1 (void) setNumerator:(int) n {
     2     //@synthesize numerator, denominator; 若是这样则
     3     //self->numerator = n;
     4     self->_abc = n;
     5 }
     6 
     7 (void) setDenominator:(int) n {
     8     self->_def = n;
     9 }
    10 
    11 (int) numerator {
    12     return self->_abc;
    13 }
    14 
    15 (int) denominator {
    16     return self->_abc;
    17 }
    如果不写@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文件

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

    MathOps.m文件

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

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

    类实例变量的扩展(extension)

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

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

    1 #import "Fraction.h"
    2 @interface Fraction() //括号里是空就是了
    3 {
    4     int MaxNum;
    5 }
    6 
    7 @property int minNum;
    8 
    9 @end

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

    协议@protocol

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

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

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

    @interface className: NSObject

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

    1 @protocol Drawing
    2 -(void)paint;   //采用的类中必须实现
    3 -(void)erase;   //采用的类中必须实现
    4 @optional
    5 -(void)outline; //采用的类中不一定实现
    6 @required
    7 -(void)showDetail; //采用的类中必须实现
    8 @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: 数组类,一个不可变,一个可变
    1 NSArray * name = [NSArray arrayWithObjects:@"zhangsan", @"lisi", @"dawang", nil];
    2 
    3 NSMutableArray * nameMutable = [NSMutableArray array];
    4 for (int i = 0; i < 10; i++) {
    5     nameMutable = [NSNumber numberWithInteger: i];
    6 }
    • NSValue: 把Foundation集合中的非对象(int、float等用NSNumber)比如C中结构体CGPoint包装(wrapping)成对象,使用时再把对象展开(unwrapping)得到CGPoint。
     1 CGPonit myPonit;
     2 NSValue * ponitObj;
     3 NSMutableArray * touchPoints = [NSMutableArray array];
     4 
     5 myPonit.x = 100;
     6 myPoint.y = 200;
     7 
     8 pointObj = [NSValue valueWithPoint:myPint];
     9 [touchPoints addObject: pointObj];
    10 
    11 myPoint = [[touchPoints lastObject]pointValue];
    • NSDictionary/NSMutableDictionary: 字典,keyValue结构
     1 NSMutableDictionary * glossary = [NSMutableDictionary dictionary];
     2 
     3 [glossary setObject:@"zhangSan" forKey:@"zhang"];
     4 [glossary setObject:@"zhaoSi" forKey:@"zhao"];
     5 
     6 NSLog(@"name zhang is: %@", [glossary objectForKey:@"zhang"]);
     7 
     8 NSDictionary * glossaryDic = 
     9 [NSDictionary dictionaryWithObjectsAndKeys:
    10 @"zhangSan", @"zhang",
    11 @"zhaoSi", @"zhao",
    12 nil];
    13 
    14 for (NSString * key in glossaryDic) {
    15     NSLog(@"%@:%@", key, [glossary objectForKey: key]);
    16 }
    • 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文件

     1 #import <Foundation/Foundation.h>  
     2   
     3 @interface SelectorDemo : NSObject  
     4 {  
     5     SEL _methodTest;  
     6 }  
     7   
     8 @property (nonatomic,assign) SEL methodTest;//这里声明为属性方便在于外部传入。  
     9   
    10 -(void)TestParentMethod;  
    11   
    12 -(void)TestSubMethod;  
    13   
    14   
    15 @end  

    .m文件

     1 #import "SelectorDemo.h"  
     2   
     3 @implementation SelectorDemo  
     4   
     5 @synthesize methodTest = _methodTest;  
     6   
     7 -(void)parentMethod  
     8 {  
     9     NSLog(@"parent method Call Success!");  
    10 }  
    11   
    12 -(void)TestParentMethod  
    13 {  
    14     if (_methodTest)  
    15     {  
    16         [self performSelector:_methodTest withObject:nil];  
    17     }  
    18 }  
    19   
    20 -(void)TestSubMethod  
    21 {  
    22     if (_methodTest)  
    23     {  
    24         [self performSelector:_methodTest withObject:nil];  
    25     }  
    26 }  
    27   
    28 @end  

    子类.h文件

    1 #import <Foundation/Foundation.h>  
    2 #import "SelectorDemo.h"  
    3   
    4 @interface SelectorSub : SelectorDemo  
    5   
    6 @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

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

    block的注意点

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

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

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

    示例代码如下: 

    1 - (void)myFourBlock
    2 {
    3     int num = 5;
    4     void (^myFourBlock)() = ^{
    5     
    6         num = 6;
    7         NSLog(@"%d",num);
    8     };
    9 }

    //发现需要的再加

    结语

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

    参考

  • 相关阅读:
    mysql 远程登陆不上
    hdu 5339 Untitled【搜索】
    SqlServer 书目
    passwordauthentication yes
    oracle 11g RAC ocfs2
    Oracle 11g RAC database on ASM, ACFS or OCFS2
    CentOS ips bonding
    Oracle 11g RAC features
    openStack 王者归来之 trivial matters
    openstack windows 2008 img
  • 原文地址:https://www.cnblogs.com/BigFeng/p/4852040.html
Copyright © 2011-2022 走看看