zoukankan      html  css  js  c++  java
  • Objective-c快速入门

    对象(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中这样的代码已经出错:

    image

    如果你选择在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块还经常作为参数传递。
  • 相关阅读:
    由1433端口入侵,浅谈sqlserver安全 (转)
    使用 Aircrack-ng 破解 WEP 和 WPA/WPA2 加密的 Wi-Fi 密码。(转)
    ZZmsvcprt.lib(MSVCP90.dll) : error LNK2005:已经在libcpmtd.lib(xmutex.obj) 中定义 .的分析解决办法 (转)
    提高D3js力导向图加载速度(转)
    Asp.Net实现FORM认证的一些使用技巧(转)
    Windows Server 2008 R2 备份和恢复 (转)
    搭建Go开发及调试环境(LiteIDE + GoClipse) -- Windows篇
    Beego源码分析(转)
    go语言实现一个简单的登录注册web小程序
    从无线安全到内网渗透(转)
  • 原文地址:https://www.cnblogs.com/ai-developers/p/4464915.html
Copyright © 2011-2022 走看看