黑马程序员——Foundation基础篇

本文详细介绍了Objective-C中的Foundation框架,包括NSRange、NSPoint、NSSize、NSRect等结构体的使用方法,以及NSString、NSArray、NSSet、NSDictionary等常用类的特点与操作技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

------Java培训、Android培训、iOS培训、.Net培训 期待与您交流! -------

本篇讲述的是Foundation框架的一些常用的结构体和常用类。

1.Foundation框架的结构体

NSRange

创建方法:
(1)NSRange r1 = {location,length};这样的方式在实际开发中并不推荐使用。
(2)一般使用的是这种: NSRange r1 = NSMakeRange(location,length);
接下来一段代码是如何获得一个子串在某一段字符串中的位置和长度。
#import <Foundation/Foundation.h>

int main()
{
    NSString *s = @"This is Foundation test,welcome to OC program!";
    NSRange r = [s rangeOfString:@"Foundation"];
    NSLog(@"\n位置是:%ld,长度是:%ld",r.location,r.length);
    return 0;
}
结果:
2015-04-16 09:31:31.916 Foundation的结构体[662:303]
位置是:8,长度是:10
使用rangeOfString查找某个小字符串在某个字符串中的范围,并将结果用NSRange来保存
上面的情况是找到了的时候,那如果子串没有找到的时候会有什么值呢?
还是利用上面的代码,把查找的子串换为@"haha",我们来看看结果
2015-04-16 09:38:27.234 Foundation的结构体[679:303]
位置是:9223372036854775807,长度是:0

位置上是什么值呢?换成%d再输出一下
2015-04-16 09:43:54.145 Foundation的结构体[704:303]
位置是:-1,长度是:0

因为原来是unsigned long,无符号,所以输出的是上面那一堆。由此我们可以知道,NSRange的返回值,查找到的时候,返回查找子串首字母的下标和子串长度;找不到的时候,location返回-1,length返回0

NSPoint/CGPoint

NSPoint和CGPoint是一样的,都是创建一个点,实际开发中使用CGPoint会更多,因为CGPoint是跨平台的。
用法:
    CGPoint point1 = NSMakePoint(10, 5);
    NSPoint point2 = CGPointMake(12, 13);
上面两种都可以,point2的使用会更多一点

注意的点:

(1)有一个特殊的点,(0,0),也就是CGPointZero
NSLog(@"%f,%f",CGPointZero.x,CGPointZero.y);
结果:
2015-04-16 10:04:04.207 Foundation的结构体[805:303] 0.000000,0.000000
(2)比较两个点是否相同(CGPointEqualToPoint)
CGPointEqualToPoint是函数__CGPointEqualToPoint的宏定义,返回的是bool型的数据,也就是如果两个点相同返回1,不同返回0
使用范例
    CGPoint point1 = NSMakePoint(10, 5);
    NSPoint point2 = CGPointMake(12, 13);
    NSLog(@"%d",CGPointEqualToPoint(point1, point2));
这两个点不同,所以结果是0

NSSize/CGSize

用法和上面讲的CGPoint类似,有两个属性:width和height
用法:
    NSSize size = CGSizeMake(20, 20);
    NSSize size2 = NSMakeSize(20,20);
    NSLog(@"%d",CGSizeEqualToSize(size, size2));
结果是:1
这里不细讲了

NSRect/CGRect

包含CGPoint 和 CGSize,用法也类似

    NSRect r1 = NSMakeRect(1, 1, 2, 3);
    NSRect r2 = CGRectMake(1, 1, 2, 3);
CGRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height);

x和y表示一个CGPoint,w和h表示CGSize

这里有一个特别需要注意的点:

CGRectContainsPoint(一个矩形中是否包含某个点(边界值不包含))

    NSRect r1 = NSMakeRect(1, 1, 2, 3);
    CGPoint p1 = CGPointMake(2, 2);
    NSLog(@"%d",CGRectContainsPoint(r1, p1));
结果:1

返回的时bool型数据,如果包含这个点返回1,不包含返回0,注意边界上的点是不包含的。

打印结构体的值

刚才在打印结构体值的时候,感觉很麻烦,下面将介绍直接打印的方式。

思路是将结构体转成字符串,再打印整个结构体
NSString *str = NSStringFromRange(r2);//将范围转成字符串
NSString *str = NSStringFromPoint(r2);//将点转成字符串
NSString *str = NSStringFromSize(r2);//将size转成字符串
NSString *str = NSStringFromRect(r2);//将Rect转成字符串
NSLog(@"%@",str);

示例:

    NSRect r1 = NSMakeRect(1, 1, 2, 3);
    CGPoint p1 = CGPointMake(3,4);
    NSString *str1 = NSStringFromRect(r1);
    NSString *str2 = NSStringFromPoint(p1);
    NSLog(@"\n%@\n%@",str1,str2);
结果:

2015-04-16 10:34:38.961 Foundation的结构体[1005:303]
{{1, 1}, {2, 3}}
{3, 4}

2.常用类

NSString(不可变字符串)和NSMutableString(可变字符串)

这个类在我们之前所讲内容中就经常有用到,它是一个不可变字符串,一旦创建就不可修改,它有一个子类NSMutableString,这是可变字符串。系统为其提供了很多的创建方法,最简单的就是NSString *s = @"test";,还有带格式创建stringWithFormat:,等,下面的一段代码中,就是使用了带格式创建一个字符串,同时可以看看NSString和NSMutableString的区别。
    int age = 25;
    //创建带格式的不可变字符串
    NSString *str = [NSString stringWithFormat:@"my age is %d",age];
    //创建带格式的可变字符串
    NSMutableString *mstr = [NSMutableString stringWithFormat:@"my age is %d",age];
    //为已经创建的可变字符串添加字符
    [mstr appendString:@"\tthis is Foundation study"];
    //不可变字符串中是没有这个方法的,它想要添加字符,只能用下面的方式
    NSString *str2 = [str stringByAppendingString:@"\t我是不可变字符串"];
    NSLog(@"\n%@\n%@\n%@",str,mstr,str2);
使用NSMutableString可以直接在后面添加字符串,但是NSString就不行,它只能调用stringByAppendingString方法后赋值给一个新的字符串,它本身的值并没有改变。
还有一些用法:
(1)删除某个子串
    int age = 25;
    //创建带格式的不可变字符串
    NSMutableString *str = [NSMutableString stringWithFormat:@"my age is %d",age];
    NSRange range = [str rangeOfString:@"is"];
    [str deleteCharactersInRange:range];
    NSLog(@"%@",str);
注意,deleteCharactersInRange:这个方法只能是NSMutableString的。
(2)将C语言字符串转成OC字符串
    NSString *s = [NSString stringWithUTF8String:"hello"];
    NSLog(@"%@",s);
“hello”是一个C语言字符串,这样转完之后变成OC字符串。
OC字符串转成C语言字符串(接着上面的代码)
    const char *s1 = [s UTF8String];
    printf("%s\n",s1);
(3)从文件中读取字符串
    NSString *file = [NSString stringWithContentsOfFile:@"/Users/liweixi/Desktop/ios-study/日志的代码/OC/常用类/常用类/main.m" encoding:NSUTF8StringEncoding error:nil];
    NSLog(@"\n%@",file);
还可以用URL
    NSURL *url = [NSURL URLWithString:@"file:///Users/liweixi/Desktop/10.c"];
    NSString *file = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
但是注意了,url中是不能有中文的,会报错的的
另外,URL可以打开网页
    NSURL *url = [NSURL URLWithString:@"https://www.baidu.com"];
    NSString *file = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];

还可以把OC中的东西写入文件

        NSString *s = @"hello foundation\n";
        [s writeToFile:@"/Users/liweixi/Desktop/test.txt" atomically:YES encoding:NSUTF8StringEncoding error:nil];

集合类

NSArray(不可变数组)

它有一个子类NSMutableArray(可变数组)

OC中的数组与C语言中的不同,可以存放多种类型
    Person *p = [[Person alloc] init];
    NSArray *a = [NSArray arrayWithObjects:p,@"hello",@"ios",@"foundation", nil];
    NSLog(@"%@",a[2]);
    NSLog(@"%@",[a objectAtIndex:2]);
上面代码可以看出,NSArray可以存放不同类型的对象,但是它不能存放基本数据类型、结构体、枚举等这些类型的数据(要存放它们在后面NSNumber的时候会讲),它只能存放OC对象,还有一点,nil不可省略,是oc数组结束的标志,因此,OC数组还不能存空值
上面的代码中也给出了取出某个对象的方法
a.利用编译器特性,像数组一样来存取:NSLog(@"%@",a[2]);
b.调用方法:NSLog(@"%@",[a objectAtIndex:2]);
那如果我想要遍历这个数组怎么做呢?这也有两种比较常用的方法
a.利用for循环
    for (id obj in a)
    {
        NSLog(@"%@",obj);
    }
但是这种方法有个小问题,需要自定义一个变量来存取下标
b.利用block
    [a enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        NSLog(@"%ld-%@",idx,obj);
    }];
每遍历一次数组元素,就会调用这个block,并且把当前元素和索引传给这个block。个人觉得这种方法很好用,stop指针相当于break
    NSLog(@"%ld",a.count);
a.count是用来求数组元素个数的。

还有一种利用编译器特性快速创建数组的方式
NSArray *a = @[p,@"hello",@"ios",@"foundation"];
怎么省事怎么来啊,但是注意,不能使用这种方式来创建NSMutableArray,因为利用这种方式创建出来的数组仍然是NSArray,如果不慎使用,可能会在运行的时候报那个,不能识别的消息传给对象的经典错误的

NSSet

感觉用法上和NSArray有点像,我们来看看它们之间的异同点、
共同点
都是集合,能存放多个OC对象
只能存放OC对象,不能存放非OC对象(基本数据类型,结构体,枚举等)
本身不可变,都有一个可变的子类
不同点
NSArray本身有顺序,但是NSSet是无序的

由于它本身无序,也就导致了它不能像数组那样来用,它没有办法取出特定的某个元素
    NSSet *s = [NSSet setWithObjects:@"ferferf",@"fergg",@"grtgr",@"fgrtgth", nil];
    //随机取出对象
    NSString *str = [s anyObject];
    NSLog(@"%@",str);
它也有个子类:NSMutableSet(可变的)。

NSDictionary

字典,它存储的时键值对,一个key对应一个object,key值不可重复
下面来看看它的几种创建方式吧
(1)
    NSDictionary *d = [NSDictionary dictionaryWithObjectsAndKeys:
                       @"jack",@"name",
                       @"25",@"age", nil];
    NSLog(@"%@",[d objectForKey:@"name"]);
结果是:jack
(2)利用数组
    NSArray *objs = @[@"jack",@"25"];
    NSArray *keys = @[@"name",@"age"];
    NSDictionary *d1 = [NSDictionary dictionaryWithObjects:objs forKeys:keys];
    NSLog(@"%@",[d1 objectForKey:@"name"]);
(3)利用编译器特性快速创建
    NSDictionary *d2 = @{
                         @"name":@"jack",
                         @"age":@"25"};
    NSLog(@"%@",[d2 objectForKey:@"name"]);
objectForKey表示按照key值取出object内容,还有一种简便写法
    id obj = d2[@"name"];
    NSLog(@"%@",obj);
同样利用
d.count 可以取出键值对的个数(注意不是所有元素,而是键值对的个数)
和数组一样,字典也可以遍历
    //字典的遍历
    //方法一
    for (id obj in d2)
    {
        NSLog(@"%@",obj);
    }
    //方法二
    [d2 enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
        NSLog(@"%@-%@",key,obj);
    }];
方法一并不好,还是使用方法二更好。
直接使用字典名来打印也是可以的
    NSLog(@"%@",d2);
结果:
2015-04-16 12:43:00.412 字典[2141:303] {
age = 25;
name = jack;
}

NSNumber和NSValue

可以将基本数据类型、结果体等包装成对象。
包装基本数据类型(NSNumber)
    NSNumber *n = [NSNumber numberWithInt:25];
    NSDictionary *d = @{
                        @"age":n
                        };
    NSLog(@"%@",d);
快速包装基本数据类型:
    NSDictionary *d = @{
                        @"age":@(25)
                        };
    NSLog(@"%@",d);
NSNumber能够包装基本数据类型,原因是因为继承了NSValue类
还可以将它转回基本数据类型
    NSInteger a = [d[@"age"] integerValue];
    NSLog(@"%d",a);
上述代码的意思是,从字典中取出key为 age 的object ,并将它转为 int型

包装结构体等可以用NSValue
    NSValue *v = [NSValue valueWithPoint:NSMakePoint(2,23)];
    NSArray *a = @[v,@"hello"];
    NSLog(@"%@",a);
结果
2015-04-16 12:59:35.278 NSNumber[2362:303] (
"NSPoint: {2, 23}",
hello
)
NSValue也可以转为结构体
    NSString *p = NSStringFromPoint([v pointValue]);
    NSLog(@"%@",p);
上述代码是将NSValue类型的v转成NSPoint类型后再转为NSString输出

NSDate

日期和时间类
    NSDate *date = [NSDate date];
    NSLog(@"%@",date);
注意,这样输出的是0时区的时间

一般需要对日期进行格式化输出
    //格式化输出日期
    NSDate *date = [NSDate date];
    NSDateFormatter *df = [[NSDateFormatter alloc] init];
    df.dateFormat = @"yyyy-MM-dd HH:mm:ss";
    NSString *today = [df stringFromDate:date];
    NSLog(@"%@",today);
结果:
2015-04-16 13:15:57.208 NSDate[2524:303] 2015-04-16 13:15:57

还可以自定义一个日期来输出
    NSString *str = @"2015-04-01 11:35:20";
    NSDateFormatter *df = [[NSDateFormatter alloc] init];
    df.dateFormat = @"yyyy-MM-dd HH:mm:ss";
    NSDate *date = [df dateFromString:str];
    NSLog(@"%@",date);
    NSString *today = [df stringFromDate:date];
    NSLog(@"%@",today);
结果:
2015-04-16 13:20:40.830 NSDate[2552:303] 2015-04-01 03:35:20 +0000
2015-04-16 13:20:40.831 NSDate[2552:303] 2015-04-01 11:35:20
使用字符串定义一个日期,将它转为一个格式化的日期,如果直接用这个日期输出,那么结果是当天0时区的时间,如果是再转成字符串,就可以得到你定义的时间了

3.应用实例

学到这里我才发现,OC其实就是使用各种方法,只要知道用什么方法,程序很快就能写出来,这就是面向对象编程的优势所在了吧
最后放一个个人认为有点不好做的小练习代码

* 统计某个目录下或者单个文件的行数(这里是统计的.m、.h和.c的代码量)

#import <Foundation/Foundation.h>
NSUInteger countFileCore(NSString *path)
{
    
    NSFileManager *manager = [NSFileManager defaultManager];
    BOOL dir = NO;
    BOOL exist = [manager fileExistsAtPath:path isDirectory:&dir];
    if (!exist) {
        NSLog(@"路径不存在");
        return 0;
    }
    if (dir)
    {
        NSArray *fileListArray = [manager contentsOfDirectoryAtPath:path error:nil];
        NSUInteger count = 0;
        for (NSString *filename in fileListArray)
        {
            NSString *fileFullPath = [NSString stringWithFormat:@"%@/%@",path,filename];
            count += countFileCore(fileFullPath);
        }
        return  count;
        
        
    }
    else
    {
        NSString *extention = [[path pathExtension] lowercaseString];
        if (  !([extention isEqualToString:@"h"]
           || [extention isEqualToString:@"m"]
           || [extention isEqualToString:@"c"]))
        {
            return 0;
        }
        //单个文件代码量统计,加载文件内容
        NSString *file = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
        NSArray *lineArray = [file componentsSeparatedByString:@"\n"];
        //替换路径
        NSRange range = [path rangeOfString:@"/Users/liweixi/Desktop/ios-study"];
        NSString *s = [path stringByReplacingCharactersInRange:range withString:@""];
        NSLog(@"\n路径:%@\n文件代码数:%ld",s,lineArray.count);
        return lineArray.count;
    }
}

int main() {
    @autoreleasepool 
    {
        NSString *filepath = @"/Users/liweixi/Desktop/ios-study";
        NSUInteger count = countFileCore(filepath);
        NSLog(@"代码量是%ld",count);
    }
    return 0;
}

基础篇的学习就到这里了,所有知识点你都get了吗?




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值