疯狂iOS讲义笔记-方法与成员变量

方法的所属性

方法是由传统的函数发展而来的。 就行为来看,函数与方法具有极高相似性,它们都可以接受定义形参,调用时都可以传入实参。

Objective-C调用函数时的传参机制与调用方法的传参机制完全相同,都是值传递,都是传入参数的副本。

方法与函数的显著不同: 在结构化的编程语言里,函数是一等公民,整个软件由一个个函数组成;在面向对象的编程语言里类才是一等公民。因此,在Objective-C语言里,方法不能独立存在,方法必须属于类和对象。

Objective-C语言中的方法的所属性主要体现在如下几方面:

  • 方法不能独立定义,只能在类体里定义。
  • 从逻辑上看,方法要么属于类本身,要么属于类的一个对象。
  • 永远不能独立执行方法,执行方法必须使用类或对象作为调用者。

形参个数可变的方法

如果在定义方法时,在最后一个形参名后增加逗号和三点(, …),则表示该形参可以接受多个参数值。

例:

#import <Foundation/Foundation.h>

@interface VarArgs : NSObject
// 定义形参可变的方法
- (void) test: (NSString*) name, ...;
@end

为了在程序中获取个数可变的形参,需要使用如下关键字。

  • va_list:这是一个类型,用于定义执行可变参数列表的指针变量。
  • va_start:这是一个函数,该函数指定开始处理可变形参的列表,并让指针变量指向可变形参列表的第一个参数。
  • va_end:结束处理可变形参,释放指针变量。
  • va_arg:该函数返回获取指针当前指向的参数的值,并将指针移动到指向下一个参数,下面的实现类对上面的test:方法提供了实现。

例:

#import <Foundation/Foundation.h>

@interface VarArgs : NSObject
// 定义形参可变的方法
- (void) test: (NSString*) name, ...;
@end

@implementation VarArgs
- (void) test: (NSString*) name, ... {
    // 使用va_list定义一个argList指针变量,该指针变量指向可变参数列表
    va_list argList;
    // 如果第一个name参数存在,才需要处理后面的参数
    if (name) {
        // 由于参数name不在参数列表里面,因此需要先处理name参数
        NSLog(@"%@", name);
        // 让argList指向第一个可变参数列表的第一个参数
        va_start(argList, name);
        // va_arg用于提取argList当前指向的参数,并让指针指向下一个参数
        // arg变量用于保存当前获取的参数,如果该参数不为nil,进入循环体
        NSString* arg = va_arg(argList, id);
        while (arg) {
            // 打印出每一个参数
            NSLog(@"%@", arg);
            // 再次提取argList当前指向的参数,并让指针指向下一个参数
            arg = va_arg(argList, id);
        }
        // 释放argList指针
        va_end(argList);
    }
}
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        VarArgs* va = [[VarArgs alloc] init];
        [va test: @"疯狂iOS讲义", @"疯狂Android讲义", @"疯狂Ajax讲义", nil];
    }
    return 0;
}

运行结果:

2022-05-09 19:53:31.263189+0800 oc.programme[24639:891729] 疯狂iOS讲义
2022-05-09 19:53:31.263412+0800 oc.programme[24639:891729] 疯狂Android讲义
2022-05-09 19:53:31.263433+0800 oc.programme[24639:891729] 疯狂Ajax讲义

最后需要指出的是,个数可变的形参只能处于形参列表的最后。也就是说,一个方法中最多只能有一个长度可变的形参。


成员变量及其运行机制

成员变量是指在类接口部分或类实现部分定义的变量,Objective-C的成员变量都是实例变量,并不支持真正的类变量。

只要实例存在,程序就可以访问该实例的实例变量,在程序中访问实例变量通过如下语法:

实例->实例变量

例:

#import <Foundation/Foundation.h>

@interface FKPerson : NSObject {
    @public
    // 定义两个实例变量
    NSString* _name;
    int _age;
}
@end

@implementation FKPerson
@end

int main(int argc, char * argv[]) {
    @autoreleasepool {
        FKPerson* p = [[FKPerson alloc] init];    // 创建FKPerson对象
        NSLog(@"p变量的_name实例变量的值是:%@, p对象的_name实例变量是:%d", p->_name, p->_age);
        // 通过指针变量来访问Person对象_name, _age实例变量。
        p->_name = @"孙悟空";
        p->_age = 500;
        NSLog(@"p变量的_name实例变量的值是:%@, p对象的_name实例变量是:%d", p->_name, p->_age);
    }
}

运行结果:

2022-05-09 21:24:34.988138+0800 oc.programme[25406:923781] p变量的_name实例变量的值是:(null), p对象的_name实例变量是:0
2022-05-09 21:24:34.988385+0800 oc.programme[25406:923781] p变量的_name实例变量的值是:孙悟空, p对象的_name实例变量是:500
Program ended with exit code: 0

从上面的程序看,成员变量无需显示初始化,只要为一个类定义了实例变量,系统会为实例变量默认被初始化为0;指针类型的变量默认被初始化为nil。


模拟类变量

Objective-C并不支持类似jave的类变量,但是可以通过内部全局变量来模拟类变量。

为了模拟类变量,可以在类实现部分定义一个static修饰的全局变量,并提供一个类方法来暴露该全局变量。

例:

#import <Foundation/Foundation.h>

@interface FKUser : NSObject
+ (NSString*) nation;
+ (void) setNation: (NSString*) newNation;
@end

// 定义全局变量
static NSString* nation;

@implementation FKUser
+ (NSString*) nation {
    return nation;
}
+ (void) setNation: (NSString *) newNation {
    if (![nation isEqualToString: newNation]) {
        nation = newNation;
    }
}
@end

int main(int argc, char * argv[]) {
    @autoreleasepool {
        [FKUser setNation: @"中国"];
        NSLog(@"nation:%@", [FKUser nation]);
    }
    return 0;
}

上面FKUser类的实现部分定义了一个nation全局变量,并实现了两个类方法用于访问、修改nation全局变量,这样即可为FKUser类模拟增加了一个nation类变量。

运行结果:

2022-05-11 19:25:26.924204+0800 oc.programme[45701:1534211] nation:中国
Program ended with exit code: 0

单例(Singleton)模式

在某些时候,程序多次创建该类的对象没有任何意义,还可能造成系统性能下降。此时程序设计需要保证该类只有一个实例。

如果一个类始终只能创建一个实例,则这个类被称为单例类。

单例类可以通过static全局变量来实现,程序考虑定义一个static全局变量,该变量用于保存自己创建的Singleton对象——每次程序需要获取该实例时,程序先判断该static全局变量是否为nil,如果该全局变量为nil,则初始化一个实例并赋值给static全局变量。

例:

#import <Foundation/Foundation.h>

@interface FKSingleton : NSObject
+ (id) instance;
@end

static id instance;

@implementation FKSingleton
+ (id) instance {
    if (!instance) {
        instance = [[super alloc] init];
    }
    return instance;
}
@end

int main(void) {
    @autoreleasepool {
        if ([FKSingleton instance] == [FKSingleton instance]) {
            // 如果两次创建单例相同打印1
            NSLog(@"1");
        } else {
            // 否则打印0
            NSLog(@"0");
        }
    }
}

运行结果:

2022-05-11 19:26:25.314829+0800 oc.programme[45720:1535024] 1
Program ended with exit code: 0

上面程序中,FKSingleton类的接口部分声明了一个instance类方法,允许程序通过该类方法来获取该类的唯一实例。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值