OC-NSArray与NSMutableArray

1.概念

OC集合类是一些非常有用的工具类,他可以用于存储多个数量不等的对象,并可以实现常用的数据结构,如栈、队列等。除此之外还可以用于保存具有映射关系的关联数组。OC的集合大致上可以分为NSArray、NSSet、NSDictionary三种体系

  • NSArray:代表有序,可重复的集合
  • NSSet:代表无序,不可重复的集合
  • NSDictionary:代表具有映射关系的集合
  1. OC集合就像一种容器,程序可以把多个对象(实际上是指针)都存进该容器中
  2. 为了保存不确定的数据,以及保存具有映射关系的数据(也被称为关联数组),OC提供了集合类,分别由NSArray、NSSet、NSDictionary这三个类簇代表,实际上也可能是他们的子类的实例(NSMutableArray、NSMutableSet、NSMutableDictionary)
  3. 集合与数组不同,数组中既可以保存基本类型的值,也可以是对象(指针变量);而集合里只能保存对象(指针变量)

2.特征

  • NSSet集合类似一个罐子,将一个对象添加到NSSet集合时,NSSet集合无法记住添加这个元素的顺序,所以NSSet里的元素不可以重复;
  • NSArray集合非常像一个数组,他可以记住每次添加元素的顺序;只是NSMutableArray的长度可变
  • NSDictionary集合也像一个罐子,他里面的每项数据都由两个值组成

从图中可以看出,如果访问NSArray集合中的元素,可以直接根据元的索引来访问;如果需要访问NSDictionary集合中的元素,则可以根据每项元素的key值来访问其中的value;如果希望访问NSSet集合中的元素,只能根据元素本身来访问

NSArray的功能与用法

  1. NSArray分别提供了类方法与实例方法来创建NSArray,两种创建方式需要传入的参数基本相似,只是类方法以array开头,实例方法以init开头
  • array:创建一个不包含任何元素的空NSArray
  • arrayWithContensOfFile:或者initWithContentsOfFile: :读取文件内容来创建NSArray
  1. NSBundle是OC中用于管理应用程序资源的类,应用程序的资源包括很多东西,比如plist文件、图像文件、nib文件、sqlite等数据库文件,甚至一些自定义的文本文件等
  2. MainBundle是NSBundle的一个类方法,[NSBundle minaBundle]返回的是应用程序的主资源包对象,主资源包包含了应用程序在安装时自带的资源文件(例如,应用的图标,默认的配置文件等都存储在主资源包中)
  3. pathForResource:ofType:NSBundle 类的一个实例方法。当你拥有一个 NSBundle 对象(比如 [NSArray mainBundle] 返回的主资源包对象)后,可以调用这个方法来获取指定资源文件的路径

具体来说:

  • pathForResource:@"data" ofType:@"plist" 中的 @"data" 是资源文件的名称(不包含文件扩展名)。
  • @"plist" 是文件的类型(扩展名)。

举例:

假设在 Xcode 项目中添加了一个名为 data.plist 的文件到主资源包中,当你调用 [[NSBundle mainBundle] pathForResource:@"data" ofType:@"plist"] 时,它会返回 data.plist 文件在应用程序沙盒中的具体路径,比如 /Users/.../AppName.app/data.plist 这样的路径字符串。之后,你就可以根据这个路径去读取文件内容,例如创建 NSArray(如果 data.plist 的内容是数组格式)等操作

  • arrayWithObject:或者initWithIbject: :创建只包含指定元素的NSArray

  • arrayWithObjects: 或者initWithObjects: :创建包含指定的N个元素的NSArray

  • 除此之外还可以使用简化版语法来创建数组

      ```c
      @[元素1,元素2,元素3,.....]
      ```
    
 NSArray* emptyArray = [NSArray array];
        //简化语法 NSArray* emptyArray = @[];
        NSString* str = @"hello";
        NSArray* singleArray = [NSArray arrayWithObject:str];
        //简化语法:NSArray* singleArray = @[str];
        NSArray* mutiArray = [NSArray arrayWithObjects:@"apple",@"cherry", nil];
        //简化语法:NSArray* mutiArray = @[@"apple",@"banana",@"cherry"];

一旦得到NSArray对象,接下来就可以调用他的方法来操作NSArray集合

//nil表示NSArray元素结束,其实这个nil并不会存入NSArray集合中。

NSArray* array = [NSArray arrayWithObjects:@"hello",@"laoda",@"what can i say",nil];
  • 查询集合元素在NSArray中的索引
[array indexOfObject:@"---"]
  • 获取元素在集合指定范围中的位置
[array indexOfObject:@"hello" inRange:NSMakeRange(2,3)];
//如果该范围没有包含该字符串对象,程序会返回9223372036854775807,这是常量NSNotFound的值
  • 获取NSArray集合中指定范围的元素
NSArray* arr = [array subarrayWithRange:NSMakeRange(5,3)];
  • 查询对应索引的元素
[array objectAtIndex:0]
[array lastObject]
  • 向数组最后追加一个元素(不管是哪种追加,都不会对原有的NSArray产生任何修改,因为NSArray本身是个不能进行修改的)程序只是返回一个新的NSArray对象
[array arrayByAddingObject:@"World"];
arrayWithObjects:
  • 向array数组的最后追加另一个数组的所有元素
array = [array arrayByAddingObjectsFromArray:[NSArray arrayWithObjects:@"OO",@"PP",@"QQ",nil]];
  • 遍历NSArray数组
for (int i = 0; 9 < array.count; i++) {
	NSLog(@"%@",[array objectAtIndex:i];
	//NSLog(@"%@",array[i];
}
  • 将NSArray集合的元素写入文件
[arr writeToFile:@"myFile.txt" atomically:YES];
  • 取出NSArray集合中的部分集合组成的新集合
[array objectsAtIndex:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(2,3)]];
[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(2,3)];
  • NSIndexSet是一个表示索引集合的类,用与表示一组索引

  • NSindexSet集合元素元素都是NSInteger对象

  • indexSetWithIndexesInRange: 是NSIndexSet的类方法,他接受一个NSRange作为参数,并返回一个包含指定范围内索引的NSIndexSet对象,所以:[NSIndexSet indexSetWithindexesInRange:NSMakeRange(2,3)];创建了一个NSIndexSet对象,该对象包含从索引2到索引4,即2,3,4;

[array objectsAtIndex:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(2, 3)]]
  • array 是一个 NSArray 类型的对象(假设是一个数组)。
  • objectsAtIndex:NSArray 的实例方法,它接受一个 NSIndexSet 对象作为参数。
  • 这行代码的作用是从 array 数组中获取由 NSIndexSet 指定索引对应的元素,并返回一个新的数组,新数组包含了原数组中指定索引位置的元素。例如,如果 array 数组包含多个元素,[array objectsAtIndex:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(2, 3)]] 会返回一个新数组,这个新数组包含了 array 数组中索引为 234 的元素。
  • 程序是如何判断数组中是否包含指定元素的?

标准:只有某个集合元素与被查找元素通过isEqual:方法比较返回Yes时,才可以认为NSArray集合中包含该元素,并不需要两个元素是同一个元素

举例:

#import<Foundation/Foundation.h>
@interface FKUser : NSObject
@property (nonatomic, copy)NSString* name;
@property (nonatomic, copy)NSString* pass;
- (id) initWithName:(NSString*)aName Withpass:(NSString*)aPass;
- (void) say:(NSString*)content
@end;

FKUser类重写isEqual:方法,标准是如果两个FKUser对象的name与pass相同,就认为他们相等

#import"FKUser.h"
@implemention FKUser
- (id) initWithName:(NSString*)name Withpass"(NSString*)aPass
{
  if (self = [super init]) {
			self->_name = aName;
    	self->_pass = aPass;
  }
  return self;
}

- (void)say:(NSString*)content
{
	NSLog(@"%@ say: @",self.name,content);
}


//重isEqqual方法的比较标准是:两个name与pass想的那就想等
- (BOOL) isEqual:(id)other
{
	if (self == other) {
    return YES;
  }
  if ([other class] == FKUser.class) {
		FKUser* target = (FKUser*)other;
    return [self.name idEqualToAtring:target.name] && [self.pass isEqualToString:target.pass];
  }
  return NO;
}

//重写了description方法,可以直接看到FKUser对象的状态
- (NSString*)description {
	return [NSString stringWithObjects:@"<FKUser[name = %@, pass = %@]>",self.name,self.pass];
}
@end

解释重写方法:

  • 首先检查两个对象是否指向同一块内存地址,如果是直接返回yes
  • 检查others是否为当前FKUser类的实例,如果不是就不进入循环,返回NO;
  • 强制转换,以便访问其name与pass属性
    • 虽然运行通过了判断语句,class确认了other是FKUser的实例,但是编译器在编译时只知道other是id类型(泛型对象)
    • 编译器不允许通过id类型直接访问FKUser的name与pass属性(因为id类型不保证有这些属性),强制转换后编译器才会认可这些属性的访问
  • 使用isEqualToString:判断两个字符串内容是否相同

对集合整体元素调用方法

NSArray允许对集合中的所有或者部分元素整体调用方法,如果只是简单的调用集合元素的方法·,则可以通过NSArray的如下两种方法进行调用:

  • 依次调用NSArray集合中的每个元素的指定方法,该方法需要传入一个SEL参数,用于指定调用哪个方法
makeObjectsPerformSelector:
  • 依次调用NSArray集合中的每个元素的指定方法(带参数),该方法的第一个SEL参数用于指定调用哪一个方法,第二个参数用于调用集合元素的方法时传入的参数
makeObjectsPerformSelector:withObject:

//eg:
NSArray* array = @[[FKUser alloc] initWithName:@"sun"  Withpass:@"123"],
									[[FKUSer alloc] initWithName:@"jie"  Withpass:@"234"],
									[[FKUser alloc] initWithName:@"zhao" Withpass:@"456"];
[array makeObjectsPerformSelector:@selector(say:) withObject:@"good morning,i am handsome"];

如果希望对集合中的所有元素进行隐式遍历,并使用元素来执行某段代码,则可以通过NSArray的如下方法来完成

  • 遍历集合中的所有元素,并且依次使用元素来指定代码块
enumerateObjectsUsingBlock:
  • 遍历集合的所有元素,并依次使用元素来执行指定的代码块,该方法可以额外的传入一个参数,用于控制遍历的选项,如反向便遍历
enumerateObjectsWithOptions:usingBlock:
  • 遍历集合中指定范围内的元素,并依次使用元素来执行指定的代码块,该方法可以额外传入一个参数,用于控制遍历的选项参数,用于控制遍历的选项,如反向遍历
enumerateObjectsAtIndexes:options:usingBlock:

示例:

    @autoreleasepool {
        NSString* s1 = @"laoda";
        NSString* s2 = @"laoer";
        NSString* s3 = @"laosan";
        NSString* s4 = @"laoba";
        NSArray* array = @[s1, s2, s3, s4];
        [array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
                    NSLog(@"%@.length = %lu",obj,[obj length]);
            NSLog(@"idx = %lu",idx);
          if(idx == 2)  {	
            *stop = 1;//改为yea那么就会停止遍历
          }
        }];
    }

上面的三个方法都需要传入一个代码块参数,这个代码块必须带三个参数,第一个参数代表正在遍历的集合元素,第二个参数代表正在遍历的集合元素的索引,第三个参数就是用于遍历集合的元素代码

示例:

NSArray* array = @[[FKUser alloc] initWithName:@"sun"  Withpass:@"123"],
									[[FKUSer alloc] initWithName:@"jie"  Withpass:@"234"],
									[[FKUser alloc] initWithName:@"zhao" Withpass:@"456"],
									[[FKUser alloc] initWithName:@"wang" Withpass:@"000"];
[array makeObjectsPerformSelector:@selector(say:) withObject:@"good morning"]
NSString* content = @"hello"; 
[array enumerateObjectsAtIndexes:
    [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(2, 2)]
    options:NSEnumerationReverse
    usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        NSLog(@"正在处理第%ld个元素:%@", idx, obj);
        [obj say:content];
    }];

对NSArray进行排序

typedef NS_ENUM(NSInteger, NSComparisonResult) {
    NSOrderedAscending  = -1,  // 升序(左 < 右)
    NSOrderedSame       = 0,   // 相同
    NSOrderedDescending = 1    // 降序(左 > 右)
};
sortedArrayUsingFunction:context:

// 比较函数:按字符串长度排序
NSInteger stringLengthComparator(id str1, id str2, void *context) {
    NSString *string1 = (NSString *)str1;
    NSString *string2 = (NSString *)str2;
    
    if ([string1 length] < [string2 length]) {
        return NSOrderedAscending;  // 升序(str1 在前)
    } else if ([string1 length] > [string2 length]) {
        return NSOrderedDescending; // 降序(str2 在前)
    } else {
        return NSOrderedSame;       // 相等
    }
}

// 使用示例
NSArray *originalArray = @[@"apple", @"cat", @"banana", @"dog"];
NSArray *sortedArray = [originalArray sortedArrayUsingFunction:stringLengthComparator context:nil];

NSLog(@"排序前: %@", originalArray);
NSLog(@"排序后: %@", sortedArray);
  • 该方法使用排序函数对集合元素进行排序,该排序函数必须返回NSOrderedDescending、NSOrderedAscending、NSOrderedSame这些枚举值,用于代表集合的大小,该方法会返回一个排好序的NSArray对象
sortedArrayUsingSelector
  //eg
@interface Person : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, assign) NSInteger age;
- (NSComparisonResult)compareByAge:(Person *)other;
@end

@implementation Person
- (NSComparisonResult)compareByAge:(Person *)other {
    return [@(self.age) compare:@(other.age)];
}
@end

// 使用示例
Person *p1 = [[Person alloc] init]; p1.age = 25;
Person *p2 = [[Person alloc] init]; p2.age = 20;
Person *p3 = [[Person alloc] init]; p3.age = 30;

NSArray *people = @[p1, p2, p3];
NSArray *sortedPeople = [people sortedArrayUsingSelector:@selector(compareByAge:)];

// 输出排序后的年龄
for (Person *person in sortedPeople) {
    NSLog(@"年龄: %ld", (long)person.age);
}
  • 该方法使用集合元素自身的方法对集合元素进行排序,集合元素必须返回NSOrderedDescending、NSOrderedAscending、NSOrderedSame这些枚举值,用于代表集合的大小,该方法会返回一个排好序的NSArray对象
sortedArrayUsingComparator:
  • 该方法使用代码块对集合元素进行排序,该代码块必须返回NSOrderedDescending、NSOrderedAscending、NSOrderedSame这些枚举值,用于返回集合大小,同样返回一个排序好的新的NSArray对象

(后续学习block在进行补充)

componentsJoinedByString:

示例:

NSString* s1 = @"laoda";
        NSString* s2 = @"laoer";
        NSString* s3 = @"laosan";
        NSString* s4 = @"laoba";
        NSArray* array = @[s1, s2, s3, s4];
        NSString* str = [array componentsJoinedByString:@"+"];
        NSLog(@"%@",str);


//输出:laoda+laoer+laosan+laoba
  • 用符号将数组中的元素(可以为空格)连接起来构成一个字符串
NSArray* arr = [str componentsSeparatedByString:@","];
  • 将字符串用指定的符号分隔开来,并存储到NSArray数组中

使用枚举器遍历NSArray集合元素

对于NSArray对象,出了可以用集合元素的索引来遍历集合元素之外,还可以调用NSArray对象的如下两种方法来返回枚举器

objectEnumerator:  
  • 返回NSArray集合的顺序枚举器
reverseObjecctEnumerator:
  • 返回NSArray的顺序枚举器

上面的两个方法都返回一个NSEumerator枚举器,该枚举器只包含如下两个方法

allObjects:
  • 获取被枚举集合中的每一个元素
nextObject:
  • 获取被枚举集合中的下一个元素

当遇到nil的时候遍历结束

使用NSEnumerator枚举器遍历集合元素示例:

#import<Foundation/Foundation.h>
int main(int argc, char* argv[]) {
  @autoreleasepool {
    //读取磁盘中的文件,用文件内容来进行初始化NSArray集合
    NSArray* array = [NSArray arrayWithContentOfFile:@"myFile.txt"];
    //获取NSArray的顺序枚举器
    NSEnumerator* en = [NSArray objectEnumerator];
    id object;
    while (object = [en nextObject]) {
      NSLog(@"%@",object);
    }
    NSLog(@“——————————————————下面逆序遍历——————————————————”);
    //获取逆序枚举器
    en = [array reverseObjectEnumerator];
    while (object = [en nextObject]) {
      NSLog(@"%@",object);
    }  
  }
}

总结:

枚举器一开始指向第一个元素之前

  1. 先获取枚举器
  2. 定义一个变量储存第一个元素
  3. 进入循环,枚举下一个元素

快速枚举(for- in)

语法格式:

for (元素类型 变量名 in 数组名) {
	NSLog(........);
  //通过变量名来遍历数据
}
  1. 声明在for循环中的元素叫迭代变量

示例

laoer
laosan
laoba
Program ended with exit code: 0 @autoreleasepool {
        NSString* s1 = @"laoda";
        NSString* s2 = @"laoer";
        NSString* s3 = @"laosan";
        NSString* s4 = @"laoba";
        NSArray* array = @[s1, s2, s3, s4];
        for (NSString* temp in array) {
            NSLog(@"%@",temp);
        }
    }

//输出
laoda
laoer
laosan
laoba

NSMutableArray

  • 是NSArray的子类

  • 仍然是一个数组,具备NSArray数组的特点,只能存储OC对象,每一个元素在内存中都是紧密相连的

  • 相对于父类NSArray的拓展:

      1. 可以进行动态的新增与删除
      1. 其他用法与NSArray一致
    
  • 创建:

 NSMutableArray* arr1 = [NSMutableArray new];
 NSMutableArray* arr2 = [[NSMutableArray alloc] init];
 NSMutableArray* arr3 = [NSMutableArray array];

三种方法创建的数组的元素是0,有意义的,因为我们可以进行动态的增加与删除元素

NSMutableArray* arr4 = [NSMutableArray arrayWithObjects:@"laoda",@"laoer",@"laosan",@"laosi", nil];

这样创建的可变数组也可以进行新增与删除

不可以使用@[–]创建NSMutableArray数组

  • 如何向可变数组中增加元素
addObject:
//将传入参数,作为可变数组参数传入

如果将另一个数组使用这个方法增加到被添加的数组中,那么原数组的长度加一,将传入的数据作为可变数组的一个元素

NSArray上存储的时id类型的指针,没有太严格的静态要求,并且其自身也是一个对象

addObjectsFromArray:

将传入数组中的每一个元素添加到被添加数组中

insertObject: atIndex:

将传入参数插入到指定下标

  • 删除可变数组中指定下标的元素
removeObjectAtIndex:
  • 删除可变数组中的指定元素
removeObject:
  • 删除指定范围中的元素
removeObject:  inRange:NSMakeRange(0,3)
  • 删除最后一个元素
removeLastObject
  • 删除所有元素
removeAllObjects:

将c类型数据转为OC类型

无论是NSArray还是NSMutableArray都只能存OC对象

先用一个OC对象把数据包装起来,然后把对象须存储到数组中

  • 自定义包装类来包装基础数据类型
  • 手动版
 CZNumber* num1 = [[CZNumber alloc] initWithIntValue:10];
        CZNumber* num2 = [[CZNumber alloc] initWithIntValue:20];
        CZNumber* num3 = [[CZNumber alloc] initWithIntValue:30];
        NSArray* arr = @[num1, num2, num3];
        CZNumber* num = arr[0];
        NSLog(@"%d",num.intValue);
        NSLog(@"%d",((CZNumber*)arr[0]).intValue);
  • 自动版

NSNumber是Foundation框架中定义好的一个类,这个类的对象的作用就是用来包装基础数据类型的

使用步骤:

  1. 先将基本数据类型包装到NSNumber对象中
  2. 再将NSNumber对象存储到NSArray数组中
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSNumber* num1 = [NSNumber numberWithInt:10];
        NSNumber* num2 = [NSNumber numberWithInt:20];
        NSNumber* num3 = [NSNumber numberWithInt:30];
        NSNumber* num4 = [NSNumber numberWithInt:40];
        NSArray* array = @[num1, num2, num3, num4];
        for (NSNumber* num in array) {
            NSLog(@"%d", num.intValue);
        }
    }
    return 0;
}


//输出结果:
10
20
30
40
  • 简写方式
NSArray* array = @[@10,@20,@30,@40];

@10:代表一个NSNumber对象,这个对象中包装的是整形的10

如果后面的数据是一个变量,需要用括号括起来

int num1 = 10;
int num2 = 20;
NSArray* arr = @[@(num1),@(num2)];
《餐馆点餐管理系统——基于Java和MySQL的课程设计解析》 在信息技术日益发达的今天,餐饮行业的数字化管理已经成为一种趋势。本次课程设计的主题是“餐馆点餐管理系统”,它结合了编程语言Java和数据库管理系统MySQL,旨在帮助初学者理解如何构建一个实际的、具有基本功能的餐饮管理软件。下面,我们将深入探讨这个系统的实现细节及其所涉及的关键知识点。 我们要关注的是数据库设计。在“res_db.sql”文件中,我们可以看到数据库的结构,可能包括菜品表、订单表、顾客信息表等。在MySQL中,我们需要创建这些表格并定义相应的字段,如菜品ID、名称、价格、库存等。此外,还要设置主键、外键来保证数据的一致性和完整性。例如,菜品ID作为主键,确保每个菜品的唯一性;订单表中的顾客ID和菜品ID则作为外键,顾客信息表和菜品表关联,形成数据间的联系。 接下来,我们来看Java部分。在这个系统中,Java主要负责前端界面的展示和后端逻辑的处理。使用Java Swing或JavaFX库可以创建用户友好的图形用户界面(GUI),让顾客能够方便地浏览菜单、下单。同时,Java还负责MySQL数据库进行交互,通过JDBC(Java Database Connectivity)API实现数据的增删查改操作。在程序中,我们需要编写SQL语句,比如INSERT用于添加新的菜品信息,SELECT用于查询所有菜品,UPDATE用于更新菜品的价格,DELETE用于删除不再提供的菜品。 在系统设计中,我们还需要考虑一些关键功能的实现。例如,“新增菜品和价格”的功能,需要用户输入菜品信息,然后通过Java程序将这些信息存储到数据库中。在显示所有菜品的功能上,程序需要从数据库获取所有菜品数据,然后在界面上动态生成列表或者表格展示。同时,为了提高用户体验,可能还需要实现搜索和排序功能,允许用户根据菜品名称或价格进行筛选。 另外,安全性也是系统设计的重要一环。在连接数据库时,要避免SQL注入攻击,可以通过预编译的PreparedStatement对象来执行SQL命令。对于用户输入的数据,需要进行验证和过滤,防止非法字符和异常值。 这个“餐馆点餐管理系统”项目涵盖了Java编程、数据库设计管理、用户界面设计等多个方面,是一个很好的学习实践平台。通过这个项目,初学者不仅可以提升编程技能,还能对数据库管理和软件工程有更深入的理解。在实际开发过程中,还会遇到调试、测试、优化等挑战,这些都是成长为专业开发者不可或缺的经验积累
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值