Objective-C类扩展与C语言宏定义实践

内容分享4小时前发布
0 0 0

25、假设你开发了一个矩形类,将其中一个方法标记为指定初始化器。现在有一个正方形类继承自矩形类,按照以下声明为正方形类添加一个初始化器方法:-(id) initWithSide: (int) side;

以下是为
Square
类添加
initWithSide:
方法的实现:


#import "Square.h"

@implementation Square : Rectangle

- (id)initWithSide:(int)side {
    self = [super init];
    if (self) {
        [self setSide:side];
    }
    return self;
}

- (void)setSide:(int)s {
    [self setWidth:s andHeight:s];
}

- (int)side {
    return self.width;
}

@end

在上述代码中,
initWithSide:
方法首先调用父类的
init
方法进行初始化,若初始化成功,则调用
setSide:
方法设置正方形的边长。

26、在Fraction类的add:方法中添加一个计数器,以统计该方法被调用的次数。如何获取计数器的值?

要在Fraction类的
add:
方法中添加计数器,可在类中定义一个静态变量作为计数器。在
add:
方法中每次调用时将该计数器加1。要获取计数器的值,可以提供一个类方法来返回该计数器的值。示例代码如下:


#import <Foundation/Foundation.h>

// Define the Fraction class
@interface Fraction : NSObject

@property int numerator, denominator;

- (void) print;
- (void) setTo: (int) n over: (int) d;
- (double) convertToNum;
- (Fraction *) add: (Fraction *) f;
- (void) reduce;

+ (int) getAddInvocationCount; // 新增类方法用于获取计数器值

@end

static int addInvocationCount = 0; // 静态计数器变量

@implementation Fraction

// 实现add:方法,每次调用计数器加1
- (Fraction *) add: (Fraction *) f {
    addInvocationCount++; // 原add:方法的实现代码
    Fraction *result = [[Fraction alloc] init];
    result.numerator = numerator * f.denominator + denominator * f.numerator;
    result.denominator = denominator * f.denominator;
    [result reduce];
    return result;
}

// 实现获取计数器值的类方法
+ (int) getAddInvocationCount {
    return addInvocationCount;
}

@end

在需要获取计数器值的地方调用
[Fraction getAddInvocationCount]
即可。

27、使用typedef和枚举数据类型,定义一个名为Day的类型,其可能的值为星期日、星期一、星期二、星期三、星期四、星期五和星期六。

可以使用如下代码来定义:


typedef enum { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday } Day;

28、使用typedef定义一个名为FractionObj的类型,以便能够编写如下语句:FractionObj f1 = [[Fraction alloc] init], f2 = [[Fraction alloc] init];

typedef Fraction *FractionObj;

29、根据以下定义:float f = 1.00; short int i = 100; long int l = 500L; double d = 15.00; 确定以下表达式的类型和值:f + i, l / d, i / l + f, l * i, f / 2, i / (d + f), l / (i * 2.0), l + i / (double) l


1. f + i:f 为 float 类型,i 为 short int 类型,根据类型转换规则,i 会转换为 float 类型,结果类型为 float,值为 101.00。
2. l / d:l 为 long int 类型,d 为 double 类型,l 会转换为 double 类型,结果类型为 double,值约为 33.33。
3. i / l + f:先算 i / l,i 为 short int 类型,l 为 long int 类型,i 先转换为 int 类型,再转换为 long int 类型,i / l 结果为 0(long int 类型),再加上 f(float 类型),0 转换为 float 类型,结果类型为 float,值为 1.00。
4. l * i:i 为 short int 类型,l 为 long int 类型,i 转换为 long int 类型,结果类型为 long int,值为 50000。
5. f / 2:2 为 int 类型,f 为 float 类型,2 转换为 float 类型,结果类型为 float,值为 0.50。
6. i / (d + f):先算 d + f,f 转换为 double 类型,d + f 结果为 double 类型,值为 16.00,i 为 short int 类型,转换为 double 类型,结果类型为 double,值约为 6.25。
7. l / (i * 2.0):i 转换为 double 类型,i * 2.0 结果为 double 类型,值为 200.00,l 转换为 double 类型,结果类型为 double,值为 2.50。
8. l + i / (double) l:先算 (double) l,l 转换为 double 类型,i 转换为 double 类型,i / (double) l 结果为 double 类型,值为 0.20,再加上 l(long int 类型,转换为 double 类型),结果类型为 double,值约为 500.20。

30、在Objective – C中,有一个
Fraction
类,现存在一个名为
MathOps
的类别对
Fraction
类进行扩展,扩展中已有
add

mul

sub

div
方法,要求扩展这个
MathOps
类别,使其还包含一个
invert
方法,该方法返回一个分数,该分数是调用者的倒数。

要扩展
MathOps
类别以包含
invert
方法,需要在接口部分添加该方法声明,并在实现部分添加方法定义。以下是扩展后的代码示例:


#import "Fraction.h"

// 接口部分添加 invert 方法声明
@interface Fraction (MathOps)

- (Fraction *) add: (Fraction *) f;
- (Fraction *) mul: (Fraction *) f;
- (Fraction *) sub: (Fraction *) f;
- (Fraction *) div: (Fraction *) f;
- (Fraction *) invert; // 添加 invert 方法声明

@end

@implementation Fraction (MathOps)

- (Fraction *) add: (Fraction *) f
{
    // To add two fractions: 
    // a/b + c/d = ((a*d) + (b*c)) / (b * d)

    Fraction *result = [[Fraction alloc] init];
    result.numerator = (self.numerator * f.denominator) + (self.denominator * f.numerator);
    result.denominator = self.denominator * f.denominator;
    [result reduce];
    return result;
}

- (Fraction *) sub: (Fraction *) f
{
    // To sub two fractions: 
    // a/b - c/d = ((a*d) - (b*c)) / (b * d)

    Fraction *result = [[Fraction alloc] init];
    result.numerator = (self.numerator * f.denominator) - (self.denominator * f.numerator);
    result.denominator = self.denominator * f.denominator;
    [result reduce];
    return result;
}

- (Fraction *) mul: (Fraction *) f
{
    Fraction *result = [[Fraction alloc] init];
    result.numerator = self.numerator * f.numerator;
    result.denominator = self.denominator * f.denominator;
    [result reduce];
    return result;
}

- (Fraction *) div: (Fraction *) f
{
    Fraction *result = [[Fraction alloc] init];
    result.numerator = self.numerator * f.denominator;
    result.denominator = self.denominator * f.numerator;
    [result reduce];
    return result;
}

// invert 方法实现
- (Fraction *) invert
{
    Fraction *result = [[Fraction alloc] init];
    result.numerator = self.denominator;
    result.denominator = self.numerator;
    [result reduce];
    return result;
}

@end

以上代码在
MathOps
类别中添加了
invert
方法,该方法返回一个分数,其分子和分母是调用者的分子和分母的交换。最后对结果进行了约分处理。

31、给Fraction类添加一个名为Comparison的类别。在这个类别中,根据以下声明添加两个方法:-(BOOL) isEqualTo: (Fraction ) f; -(int) compare: (Fraction ) f; 第一个方法在两个分数相同时返回YES,不同时返回NO。注意比较分数时,例如比较3/4和6/8应返回YES。第二个方法,若接收者小于参数表示的分数则返回 -1,若两者相等则返回0,若接收者大于参数表示的分数则返回1。

以下是实现该需求的代码示例:


#import "Fraction.h"

@interface Fraction (Comparison)

-(BOOL) isEqualTo: (Fraction *) f;
-(int) compare: (Fraction *) f;

@end

@implementation Fraction (Comparison)

-(BOOL) isEqualTo: (Fraction *) f {
    Fraction *selfReduced = [[Fraction alloc] init];
    selfReduced.numerator = self.numerator;
    selfReduced.denominator = self.denominator;
    [selfReduced reduce];

    Fraction *fReduced = [[Fraction alloc] init];
    fReduced.numerator = f.numerator;
    fReduced.denominator = f.denominator;
    [fReduced reduce];

    return (selfReduced.numerator == fReduced.numerator) && (selfReduced.denominator == fReduced.denominator);
}

-(int) compare: (Fraction *) f {
    double selfValue = (double)self.numerator / self.denominator;
    double fValue = (double)f.numerator / f.denominator;

    if (selfValue < fValue) {
        return -1;
    } else if (selfValue == fValue) {
        return 0;
    } else {
        return 1;
    }
}

@end

上述代码中,首先在接口部分声明了
isEqualTo:

compare:
两个方法。在实现部分,
isEqualTo:
方法将两个分数先进行约分,然后比较约分后的分子和分母是否相同;
compare:
方法将两个分数转换为小数进行比较,根据比较结果返回 -1、0 或 1。

32、为一个名为Calculator的类添加一个名为Trig的类别。在该类别中添加计算正弦、余弦和正切的方法,其声明如下:-(double) sin; -(double) cos; -(double) tan;

可以按照以下步骤为
Calculator
类添加
Trig
类别并实现相应方法:

首先,在代码中创建
Calculator
类的
Trig
类别。 由于
sin()

cos()

tan()
函数是标准C库函数,在导入
Foundation.h
时会自动导入
math.h
头文件,可直接使用这些函数来实现类别中的方法。

以下是示例代码:


#import <Foundation/Foundation.h>

@interface Calculator: NSObject

// accumulator methods
- (void) setAccumulator: (double) value;
- (void) clear;
- (double) accumulator;

// arithmetic methods
- (void) add: (double) value;
- (void) subtract: (double) value;
- (void) multiply: (double) value;
- (void) divide: (double) value;

@end

@interface Calculator (Trig)

- (double) sin;
- (double) cos;
- (double) tan;

@end

@implementation Calculator (Trig)

- (double) sin {
    return sin(self.accumulator);
}

- (double) cos {
    return cos(self.accumulator);
}

- (double) tan {
    return tan(self.accumulator);
}

@end

上述代码中,在
Calculator
类的
Trig
类别里实现了
sin

cos

tan
方法,它们分别调用标准C库函数计算累加器值的正弦、余弦和正切。

33、给定以下接口部分:
@interface Square: NSObject -(Square *) initWithSide: (int) s; -(void) setSide: (int) s; -(int) side; -(int) area; -(int) perimeter; @end #import "Rectangle.h" @implementation Square { Rectangle *rect; } // 在此插入 Square 方法... @end
完成 Square 类的实现部分以及一个测试程序来检查其方法。注意:记得重写
init
方法,因为
initWithSide:
将是指定的初始化方法。

以下是 Square 类的完整实现以及测试程序:


#import <Foundation/Foundation.h>
#import "Rectangle.h"

@interface Square: NSObject
-(Square *) initWithSide: (int) s;
-(void) setSide: (int) s;
-(int) side;
-(int) area;
-(int) perimeter;
@end

@implementation Square {
    Rectangle *rect;
}

-(instancetype)init {
    return [self initWithSide: 0];
}

-(Square *)initWithSide: (int) s {
    self = [super init];
    if (self) {
        rect = [[Rectangle alloc] init];
        [self setSide: s];
    }
    return self;
}

-(void)setSide: (int) s {
    [rect setWidth: s andHeight: s];
}

-(int)side {
    return rect.width;
}

-(int)area {
    return rect.width * rect.height;
}

-(int)perimeter {
    return 2 * (rect.width + rect.height);
}

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Square *square = [[Square alloc] initWithSide: 5];
        NSLog(@"Side: %d", [square side]);
        NSLog(@"Area: %d", [square area]);
        NSLog(@"Perimeter: %d", [square perimeter]);
    }
    return 0;
}

上述代码中,
Square
类使用
Rectangle
作为组合对象。
initWithSide:
是指定初始化方法,它会初始化
Rectangle
对象并设置边长。
setSide:
方法用于设置边长,
side
方法用于获取边长,
area
方法计算面积,
perimeter
方法计算周长。在
main
函数中,创建了一个边长为 5 的
Square
对象并测试其方法。

34、在你的机器上找到系统头文件limits.h和float.h。检查这些文件的内容。如果这些文件包含其他头文件,也务必追踪并检查它们的内容。

要完成这个任务,不同操作系统的操作方式不同。

在Linux或macOS系统中,可使用命令行工具查找,如使用以下命令(可能需要管理员权限):


find / -name limits.h
find / -name float.h

找到文件后,可用文本编辑器(如vim、nano)打开查看内容。若文件包含其他头文件,可根据文件中的包含语句,按同样方法查找并查看。

在Windows系统中,可通过文件资源管理器搜索这两个文件,找到后用文本编辑器(如记事本、VS Code)打开查看,同样要处理包含的其他头文件。

35、定义一个名为 MAX3 的宏,用于求出三个值中的最大值。编写一个程序来测试这个宏的定义。

可以使用已有的
MAX
宏来定义
MAX3
宏,定义如下:


#define MAX3(a, b, c) MAX(MAX(a, b), c)

测试程序示例(以 C 语言为例):


#include <stdio.h>

#define MAX(a,b) ( ((a) > (b)) ? (a) : (b) )
#define MAX3(a, b, c) MAX(MAX(a, b), c)

int main() {
    int x = 10, y = 20, z = 15;
    int max = MAX3(x, y, z);
    printf("三个数中的最大值是: %d
", max);
    return 0;
}

36、编写一个名为 IS_UPPER_CASE 的宏,如果一个字符是大写字母,则该宏返回非零值。


#define IS_UPPER_CASE(x) ( ((x) >= 'A') && ((x) <= 'Z') )

37、编写一个名为 IS_ALPHABETIC 的宏,如果一个字符是字母字符,则该宏返回非零值。请定义该宏,并给出宏中可能用到的 IS_LOWER_CASE 宏和 IS_UPPER_CASE 宏的定义。


#define IS_ALPHABETIC(x) (IS_LOWER_CASE(x) || IS_UPPER_CASE(x))

其中
IS_LOWER_CASE
宏定义为:


#define IS_LOWER_CASE(x) ( ((x) >= 'a') && ((x) <= 'z') )


IS_UPPER_CASE
宏定义为:


#define IS_UPPER_CASE(x) ( ((x) >= 'A') && ((x) <= 'Z') )

38、编写一个名为 ABSOLUTE_VALUE 的宏,用于计算其参数的绝对值。确保该宏能正确计算类似 ABSOLUTE_VALUE (x + delta) 这样的表达式。


#define ABSOLUTE_VALUE(x) ((x) < 0 ? -(x) : (x))

此宏定义中,使用三元运算符判断参数`x`是否小于 0,若小于 0 则取其相反数,否则保持不变。同时使用括号确保在计算复杂表达式时能得到正确结果。

39、在分数计算器应用程序中添加一个“转换”按钮。当按下该按钮时,使用Fraction类的convertToNum方法生成分数结果的数值表示。将该结果转换为字符串并显示在计算器的显示屏上。

可按以下步骤实现:

在应用界面设计中添加一个“转换”按钮; 为“转换”按钮绑定点击事件处理方法; 在点击事件处理方法中,调用
Fraction
类的
convertToNum
方法得到分数结果的数值表示; 将得到的数值结果转换为字符串; 把转换后的字符串显示在计算器的显示屏上。

40、你可以为应用程序添加一个将显示在 iPhone 主屏幕上的图标。对于普通尺寸的图标(iPhone 3GS 及更早机型),图标大小应为 57×57 像素。对于视网膜显示屏的 iPhone(iPhone 4 及以后机型),图标图像文件应为 114×114 像素。在互联网上找到一个合适的计算器图像,并将分数计算器设置为使用此图像作为其应用程序图标。

设置分数计算器应用程序图标

搜索图标图像
– 在互联网上搜索合适的计算器图像。

准备图标文件
– 若应用需适配 iPhone 3GS 及更早机型,准备 57×57 像素 的图标。
– 若应用需适配 iPhone 4 及以后机型,准备 114×114 像素 的图标。

添加图标
– 将图标图像文件添加到相应的应用程序图标设置区域。

完成设置
– 完成分数计算器应用程序图标的设置。

41、如何为计算器按钮赋予自定义外观?

要让计算器按钮有自定义外观,可按以下步骤操作:

先把自己的图片添加到项目里(将图片拖入左窗格) 接着在检查器窗口把按钮类型设为“自定义” 再把“图像”设置成刚复制到项目中的文件

使用这种自定义图片的分数计算器能从苹果应用商店免费下载,其源代码发布在论坛 classroomM.com/objective-c 上。

© 版权声明

相关文章

暂无评论

none
暂无评论...