首页 文章 精选 留言 我的

精选列表

搜索[学习],共10000篇文章
优秀的个人博客,低调大师

JAVA 并发编程学习(1)之基本概念

1,为什么需要并发? 在早期计算机中没有操作系统,一台计算机从头到尾只执行一个程序,如果这个程序的任务是先进行CPU计算再把计算结果写入文件。那么,在进行CPU计算时,这台计算机的IO模块是空闲的,把计算结果写入文件中时,这台计算机的CPU是空闲的。 为此,引入了操作系统。这样,在一台计算机中可以运行多个程序了。由操作系统来管理多个程序的运行,一个程序在进行CPU计算的同时,另一个程序可以进行IO操作。提高了计算机的利用率(CPU和IO操作 可以同时在发生了) 引入操作系统之后,不可避免地出现了进程这个概念。因为操作系统管理若干个程序了,而每个运行中的程序可以用进程来表示(进程的动态性)。 那为什么还需要线程呢? ①进程之间需要通信、需要共享一些数据,需要协作……这些用线程来“表示”更方便。因为,不同进程的地址空间是相互独立的,一个进程不能直接访问另一个进程的地址空间。一个进程内部的多个线程共享这个进程状态空间,如果把数据的共享放到线程这个层次来实现,就方便多了。 ②进一步提高资源利用率---这个有点类似于:从没有操作系统的计算机到有操作系统的计算机转变---这里是从没有线程到有线程转变。 2,我们就是因为方便数据共享……一些原因引入了线程,那么多个线程同时访问一个可变的变量时,这个变量到底处理哪一个状态?这就存在一种线程安全性问题。 3,什么是线程安全性 讨论线程安全性针对的是 类。核心就是正确性。即,某个类的行为和其规范完全一致:即,我写了一个类,这个类具有哪些功能,需要完成哪些操作……这些是类的规范;而多个线程运行这个类的代码时,其执行效果和规范描述的要一致。 当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协调,这个类都能表现出正确的行为,那么就称这个类是线程安全的。 4,无状态对象 5,Race Condition 竞态条件 ①读--修改--写入 ②check--then--act 本文转自hapjin博客园博客,原文链接:http://www.cnblogs.com/hapjin/,如需转载请自行联系原作者

优秀的个人博客,低调大师

【案例学习】芬兰铁路的 Docker 使用实践分享

写在前面 VR集团是一家经营芬兰铁路的国有公司, 每年提供8200万辆客运列车服务并且可以运输3600万吨货物。拥有150多年历史的运输业务分成了不同的部门,这些部门都有各自的技术团队,但整个集团却没有内部的开发团队,因此每个部门都会利用外部供应商和合作伙伴提供的技术支持来满足他们对应用程序开发的需求。 在DockerCon 欧洲大会的第二天,VR集团的集成经理Markus Niskanen和埃森哲公司解决方案架构师Oscar Renalias讲述了他们是如何共同合作,为芬兰铁路的关键业务(包括预订和通勤等应用程序)进行现代化改造。 合作提高效率 芬兰铁路公司开始与埃森哲公司进行长期合作,共同设计了一款基于Docker企业版(EE)的全新通用应用程序平台。借助埃森哲公司的“容器迁移工厂(Container Migration Factor

优秀的个人博客,低调大师

python标准库学习5 ---bisect — Array bisection algorithm

#coding=utf-8 import bisect list = [ 1 , 2 , 3 , 4 , 6 , 7 , 8 , 9 ] #假定list已经排序 print bisect.bisect_left( list , 5 ) #返回5应该插入的索引位置 print bisect.bisect_right( list , 5 ) print bisect.bisect( list , 5 ) bisect.insort_left( list , 5 , 0 , len ( list )) print list bisect.insort_right( list , 5 ) print list def index(a, x): 'Locate the leftmost value exactly equal to x' i = bisect_left(a, x) if i ! = len (a) and a[i] = = x: return i raise ValueError def find_lt(a, x): 'Find rightmost value less than x' i = bisect_left(a, x) if i: return a[i - 1 ] raise ValueError def find_le(a, x): 'Find rightmost value less than or equal to x' i = bisect_right(a, x) if i: return a[i - 1 ] raise ValueError def find_gt(a, x): 'Find leftmost value greater than x' i = bisect_right(a, x) if i ! = len (a): return a[i] raise ValueError def find_ge(a, x): 'Find leftmost item greater than or equal to x' i = bisect_left(a, x) if i ! = len (a): return a[i] raise ValueError >>> def grade(score, breakpoints = [ 60 , 70 , 80 , 90 ], grades = 'FDCBA' ): ... i = bisect(breakpoints, score) ... return grades[i] ... >>> [grade(score) for score in [ 33 , 99 , 77 , 70 , 89 , 90 , 100 ]] [ 'F' , 'A' , 'C' , 'C' , 'B' , 'A' , 'A' ] >>> data = [( 'red' , 5 ), ( 'blue' , 1 ), ( 'yellow' , 8 ), ( 'black' , 0 )] >>> data.sort(key = lambda r: r[ 1 ]) >>> keys = [r[ 1 ] for r in data] # precomputed list of keys >>> data[bisect_left(keys, 0 )] ( 'black' , 0 ) >>> data[bisect_left(keys, 1 )] ( 'blue' , 1 ) >>> data[bisect_left(keys, 5 )] ( 'red' , 5 ) >>> data[bisect_left(keys, 8 )] ( 'yellow' , 8 ) ============================================================================== 本文转自被遗忘的博客园博客,原文链接:http://www.cnblogs.com/rollenholt/archive/2011/11/26/2264244.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

docker学习笔记001-docker 安装方法介绍

docker Setup docker推荐使用version 1.13或者更高版本 docker 包含社区版和企业版Community Edition (CE)andEnterprise Edition (EE). 支持多种平台 DeskTop:Mac、Windows Cloud:Amazon 、Microsoft Server:CentOs、OracleLinux、Ubuntu、Debian、Red Hat Enterprise Linux 安装docker CE 启动一个docker CE,需要确认前置要求,再执行安装操作。EE版本是收费版本不做介绍 前置要求 OS要求、老版本要求:docker docker-engine查看 安装 1.Docker’s repositories安装 Install required packages.yum-utilsprovides theyum-config-managerutility, anddevice-mapper-persistent-dataandlvm2are required by thedevicemapperstorage driver. $ sudo yum install -y yum-utils \ device-mapper-persistent-data \ lvm2 Use the following command to set up thestablerepository. You always need thestablerepository, even if you want to install builds from theedgeortestrepositories as well. $ sudo yum-config-manager \ --add-repo \ https://download.docker.com/linux/centos/docker-ce.repo Optional: Enable theedgeandtestrepositories. These repositories are included in thedocker.repofile above but are disabled by default. You can enable them alongside the stable repository. $ sudo yum-config-manager --enable docker-ce-edge $ sudo yum-config-manager --enable docker-ce-test You can disable theedgeortestrepository by running theyum-config-managercommand with the--disableflag. To re-enable it, use the--enableflag. The following command disables theedgerepository. $ sudo yum-config-manager --disable docker-ce-edge Install the latest version of Docker CE, or go to the next step to install a specific version. $ sudo yum install docker-ce Start Docker. $ sudo systemctl start docker Verify thatdockeris installed correctly by running thehello-worldimage. $ sudo docker run hello-world 2.下载rpm,手动安装 从这下载 https://download.docker.com/linux/centos/7/x86_64/stable/Packages/ Install Docker CE, changing the path below to the path where you downloaded the Docker package. $ sudo yum install /path/to/package.rpm 3.scripts脚本自动安装 4.卸载 Uninstall the Docker package: $ sudo yum remove docker-ce Images, containers, volumes, or customized configuration files on your host are not automatically removed. To delete all images, containers, and volumes: $ sudo rm -rf /var/lib/docker You must delete any edited configuration files manually.

优秀的个人博客,低调大师

Objective-C 学习第九天

一、 框架: 系统或者第三方事先写好的写很牛X功能的类,把这些类交给我们使用,这些类的集合就叫框架. Foundation框架: 是一个包,有很多类和函数,定义了一些数据类型.这个框架中的类都是一些最基础的类.其他的框架都是基于Foundation框架的. UIKit. AVFoundation. ...... NSString 1). NSString是一个数据类型,保存OC字符串. NSString的本质是一个类. 最标准的创建NSString对象的方法:NSString *str1 = [NSString new]; NSString *str2 = [[NSString alloc] init]; NSString *str3 = [NSString string]; 使用这种方式创建的字符串是一个空的字符. @"" NSString 对象是用来存储字符串的. 2). NSString是OC中最常用的一个类,所以OC提供了一种更为快速的创建字符串对象的方式. 使用前缀@ @"jack": 本质是一个NSString对象,存储的是"jack"这个字符串 NSString *str1 = @"rose"; a. @"rose"本质是一个NSString对象,存储的是字符串"rose" b. 将这个字符串对象的地址返回赋值给str1指针 格式控制符%p: 打印指针变量的值,打印地址 格式控制符%@: 打印指针指向的对象 NSString对象的恒定性 1). 当我们使用简要的创建字符串对象的时候,也就是使用OC字符串常量来初始化字符串指针的时候,这个字符串对象是存储在常量区的. NSString *str = @"jack"; 当我们调用NSString的类方法来创建对象的时候, 创建的对象是存储在堆区的. NSString *str = [NSString stringWithFormat:@"jack"]; NSString *str = [NSString new]; 2). 恒定性 当在内存中创建一个字符串对象后,这个字符串对象的内容就无法更改. 当我们重新为字符串指针初始化值的时候,并不是修改原来的字符串对象,而是重新的创建一个字符串对象,将这个字符串对象的地址重新赋值给字符串指针变量. 3). 当系统准备要在内存中创建字符串对象的时候,会先检查内存中是否有相同内容的字符串对象,如果有直接指向,如果没有才会重新创建. 4). 存储在常量区的数据不会被回收,所以存储在常量区的字符串也不会被回收. NSString类中使用频率最高的方法 1). 使用拼接的方式创建一个NSString对象 + (instancetype)stringWithFormat:(NSString *)format,... int age = 10; NSString *str = @"jack"; NSString *newStr = [NSString stringWithFormat:@"大家好,我叫%@,今年%d岁",str,age]; 2). 得到字符串的长度 @property (readonly) NSUInteger length; NSString *str = @"jack"; NSUInteger len = str.length; 3). 得到字符串当中指定下标的字符 - (unichar)characterAtIndex:(NSUInteger)index; 返回值是unichar类型的,要打印的话使用%C NSString *str = @"jack"; unichar ch = [str characterAtIndex:2]; NSLog(@"ch = %C", ch); 4). 判断两个字符串的内容是否相等 a. 不能使用==来判断OC字符串的内容是否相同 b. == 运算符的作用: 比较左右两边的数据是否相同. c. 所以如果我们要比较两个OC字符串的内容是否相同,不能使用==去比较.因为==比较的是字符串指针变量的值,而我们比较的是字符串的内容 - (BOOL)isEqualToString:(NSString *) aString; 可以比较字符串的内容 NSString *str1 = @"jack"; NSString *str2 = @"jack"; [str1 isEqualToString:str2]; 5). 将C语言的字符串转换为OC字符串 + (instancetype)stringWithUTF8String:(NSString *)string; char *str = "jack"; NSString *str1 = [NSString stringWithUTF8String: str]; 6). 将OC字符串转换为C语言字符串 @property (nullable, readonly) __strong const char *UTF8String; NSString *str = @"jack"; const char *str1 = str.UTF*String; 字符串读写 1). 将一个字符串写入到磁盘上的某一个文件 (BOOL) writeToFile:(NSString *)path atomically:(BOOL)userAuxiliaryFile encoding:(NSStringEncoding)enc error:(NSError **)error; 参数1: 将字符串内容写入到哪一个文件之中,写上文件的路径. 参数2: YES,先将内容写入到一个临时文件,如果成功过再搬到指定的目录; NO,直接将内容写入到指定的文件,不安全,效率高 参数3: 指定写入的时候的编码.一般情况下使用UTF8. NSUTF8StringEncoding 参数4: 二级指针,要传递一个NSError指针的地址.如果写入成功,这个指针的值就是nil,如果失败,这个指针就会指向一个错误对象,这个对象描述了发生错误的信息. err.localizedDescription中存储发生错误的信息 返回值是BOOL类型,代表是否写入成功. NSString *str = @"jack"; NSError *err; [str writeToFile:@"/Users/Itcast/Desktop/abc.txt", atomically:NO encoding:NSUTF8StringEncoding error:&err]; 2). 从磁盘文件读取内容 (instancetype) stringWithContentsOfFile:(NSString *)path encoding:(NSStringEncoding)enc error:(NSError **)error; 参数1:文件的路径 参数2:使用的编码NSUTF8StringEncoding 参数3:错误对象 NSError *err; [NSString stringWithContentsOfFile:@"/Users/Itcast/Desktop/abc.txt" encoding:NSUTF8StringEncoding error:&err]; 使用URL来读写字符串数据. 1). 优势: 皆可以读取本地磁盘文件,还可以读写网页文件、ftp服务器文件 2). 不同类型的URL地址的写法 a. 本地磁盘文件: file://+路径---->file:///Users/Itcast/Desktop/abc.txt b. 网页地址: http://www.baidu.com/ c. ftp服务器文件的地址: ftp://server.itcast.cn/1.txt 将不同类型的地址封装在NSURL对象中 a. 从指定资源路径读取文本内容 (nullable instancetype)stringWithContentsOfURL:(NSURL *)url encoding:(NSStringEncoding)enc error:(NSError **)error; b. 将字符串的内容写入到资源路径中 (BOOL)writeToURL:(NSURL *)url atomically:(BOOL)useAuxiliaryFile encoding:(NSStringEncoding)enc error:(NSError **)error; c. 如果要向网页或者ftp写内容要有权限. NSURL *u1 = [NSURL URLWithString:@"http://www.itcast.cn"]; NSString *str = [NSString stringWithContentsOfURL:u1 encoding:NSUTF8StringEncoding error:nil]; NSURL *u1 = [NSURL URLWithString:@"file:///Users/Itcast/Desktop/abc.txt"]; NSString *str = @"hehehe"; BOOL res = [str writeToURL:u1 atomically:NO encoding:NSUTF8StringEncoding error:nil]; 字符串比较 1). 不忽略大小写 (NSComparisonResult)compare:(NSString *)string; NSString *str1 = @"hehehe"; NSString *str2 = @"jack"; NSComparisonResult res = [str compare:str2]; swith(res){ case NSOrderedAscending://str1小 break; case NSOrderedSame://一样大 break; case NSOrderedDescending://str2小 break; default: break; } 2). 忽略大小写 NSString *str1 = @"hehehe"; NSString *str2 = @"JACK"; NSComparisonResult res = [str compare:str2 option:NSCaseInsensitiveSearch]; swith(res){ case NSOrderedAscending://str1小 break; case NSOrderedSame://一样大 break; case NSOrderedDescending://str2小 break; default: break; } 3). 比较字符串中的数字 NSString *str1 = @"hehehe001"; NSString *str2 = @"hehehe002"; NSComparisonResult res = [str compare:str2 option:NSNumericSearch];// 只能比格式固定的 swith(res){ case NSOrderedAscending://str1小 break; case NSOrderedSame://一样大 break; case NSOrderedDescending://str2小 break; default: break; } 4). 判断是否以某个字符串开头 NSString *str = @"http://www.baidu.com/"; BOOL res = [str hasPrefix:@"http://"]; 5). 判断是否以某个字符串结束 NSString *str = @"/Users/Apple/Music/我们不一样.mp3"; BOOL res = [str hasSuffix:@".mp3"]; 在主串中搜索子串 1). 从前往后 - (NSRange) rangeOfString:(NSString *)searchString; 返回值NSRange类型的结构体变量typedef struct _NSRange{ NSUInteger location;//代表子串在主串出现的下标 NSUInteger length;//代表子串在主串中匹配的长度 } NSRange;NSString *str = @"i love itcast!"; // 在str字符串中搜索@"love"出现的范围 NSRange range = [str rangeOfString:@"love"]; if(range.location==NSNotFound){ // 没有找到 } else { // 找到了 } 或者 if(range.length==0){ // 没有找到 } else { // 找到了 } 2). 从后往前NSString *str = @"i love itcast love!"; // 在str字符串中搜索@"love"出现的范围 NSRange range = [str rangeOfString:@"love" options: NSBackwardsSearch] NSRange结构体 1). 是Foundation框架中定义的一个结构体typedef struct _NSRange{ NSUInteger location;//代表子串在主串出现的下标 NSUInteger length;//代表子串在主串中匹配的长度 } NSRange; NSRange range; // 这个结构体变量一般情况下用来表示一段范围,特别用在子串在主串中的范围. 2). 声明并初始化结构体变量的方式 a. 最原始的方式NSRange range; range.location = 3; range.length = 4; b. 第二种方式: NSRange range = {3, 7}; c. 第三种方式: NSRange range = {.location = 3, .length=7}; d. Foundation框架中定义了一个函数,这个函数可以快速的创建一个NSRange结构体. NSMakeRange(loc, len);返回一个指定属性的NSRange结构体变量 NSRange range = NSMakeRange(3,7); 5. 可以将NSRange结构体变量转换为NSString. NSRange range = NSMakeRange(3,7); NSString *str = NSStringFromRange(range); 字符串截取 1). 取到字符串中的一部分 (NSString *)substringFromIndex(NSUIntege)from; 从指定的下标处一直截取到最后 NSString *str = @"背景连锁酒店分开计算懒死了"; NSString *newStr = [str substringFromIndex:3]; 2). 从第0个开始截取指定的个数 (NSString *)substringToIndex(NSUIntege)to; 3). 从指定位置截取指定长度的字符串 (NSString *)substringWithRange(NSRange)range; 字符串替换 1). (NSString *)stringByReplacingOccurrencesOfString:(NSString *)target withString:(NSString *)replacement; 将字符串中第一个参数替换为第二个参数,原来的指针指向的内容是不会变的,新串是以方法的返回值返回的. NSString *str = @"背景连锁酒店分开计算懒死了"; NSString *newStr = [str stringByReplacingOccurrencesOfString:@"背景" withString:@"广州"]; 字符串数据转换为其他类型 @property (readonly)double doubleValue; @property (readonly)float floatValue; @property (readonly)int intValue; @property (readonly)NSUINteger integerValue; @property (readonly)long long longLongValue; @property (readonly)BOOL boolValue; 转换注意: 其他 1). 去掉字符串前后的空格 NSString *str = @" Jack "; [str stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; 2). 将字符串转换为大写或者小写 NSString *str = @" Jack "; [str uppercaseString]; [str lowercaseString]; 二、 NSMutableString 1). 是Foundation框架中的一个类,从NSString继承,是用来存储字符串数据的. 2). NSMutableString在父类NSString的基础之上做扩展,存储在NSMutableString对象中的数据具有可变性,不会新创建对象. NSMutableString的用法 1). 创建对象 NSMutableString *str = [NSMutableString string]; [str appendString:@"jack"]; 2). 往可变字符串对象中追加字符串 (void)appendString:(NSString *)aString;// 直接追加内容 (void)appendFormat:(NSString *)format...;// 以拼接的方式往可变字符串对象中追加内容 3). 创建NSMutableString对象时,不能使用如下方式: NSMutableString *str = @"jack"; 4). NSMutableString做大批量的字符串拼接,速度快,因为NSMutableString只有一个,每次修改的时候直接修改对象的内容 使用建议 1). 平时使用,还是使用NSString,因为效率高 2). 大批量的数据拼接的时候使用NSMutableString 10次以上使用NSMutableString. NSArray 1). 是Foundation框架中的一个类,用来存储多个数据,具备数组功能,所以NSArray是OC中的数组 2). 特点: a. 只能存储OC对象 b. 长度固定,一旦NSArray数组创建完毕之后,元素的长度固定,无法新增、删除元素. c. 每一个元素都是紧密相连的,每一个元素仍然有自己的下标. d. 元素的类型是id类型的 3). NSArray数组的创建 1). 因为是一个类,所以就是创建NSArray对象.NSArray *arr1 = [NSArray new]; NSArray *arr2 = [[NSArray alloc] init]; NSArray *arr3 = [NSArray array]; 这样创建出来的NSArray数组的元素的个数是0个,因为长度固定,所以没有任何意义. 2). 创建数组的同时指定一个数组的元素,仍然没有意义NSArray *arr1 = [NSArray arrayWithObject:@"jack"]; 3). 最常用创建NSArray数组的方式. + (instancetype)arrayWithObjects:(ObjectType)firstObj,...NSArray *arr1 = [NSArray arrayWithObjects:@"jack",@"rose",@"lili",nil]; 4). 创建NSArray简要方式 NSArray *arr = @[@"jack", @"rose", @"lili"]; 5). 使用注意 a. 只能存储OC对象,不能存储非OC对象 b. 将元素写完之后,最后要写一个nil,表示元素到此结束了 NSArray数组的编译 1). for循环 原理: 将下标挨个遍历出来 NSArray *arr = @[@"jack",@"rose"]; for(int i=0;i<arr.count;i++){ //NSLog(@"%@",arr[i]); NSLog(@"%@", [arr objectAtIndex:i]); } 2). 使用增强for循环 a. 语法格式: for(元素类型 变量名 in 数组名){ 直接通过变量名拿到数组中的每一个元素 }NSArray *arr = @[@"jack",@"rose"]; for(NSString *str in arr){ NSLog(@"%@", str); } b. 声明在for()中的变量叫做迭代变量 c. 执行变量 将数组中的第一个元素的值赋值给迭代变量,执行循环体 ... 结束循环 d. 语法总结 -> 迭代变量的类型和数组中的元素的类型保持一致 -> 迭代变量的名称可以任意取 -> in是固定的 -> 遍历那个数组就将数组写在in后面 -> 循环体里面,迭代变量的值就是元素的值 当NSArray数组中存储的数据类型不一致的时候,迭代变量的类型建议使用id类型 使用block遍历 (void) enumerateObjectsUsingBlock:(void (^)OjbectType obj, NSUInteger idx, BOOL *stop))block; 这是一个方法,这个方法作用来遍历数组中的每一个元素 NSArray *arr = @[@"jack",@"rose"]; // 将arr数组中的每一个元素遍历出来 [arr enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop){ NSLog(@"%@", obj); // 如果想停止循环,就将*stop设置为YES }]; NSArray和NSString 1). 将数组中元素连接起来组成一个新的字符串 (NSString *)componentsJoinedByString:(NSString *)separator 参数: 连接符 NSArray *arr = @[@"jack", @"rose", @"lili"]; NSString *str = [arr componentsJoinedByString:@"#"]; 2). 将字符串按指定分隔符分割 NSString *str = @"北京,昌平区,传智"; // 使用字符串进行分割 NSArray *arr = [str componentsSeparatedByString:","]; NSMutableArray是NSArray的子类 1). NSMutableArray仍然是一个数组,就被NSArray的特点,只能存储OC对象,每一个元素是紧密相连的。 2). NSMutableArray相对于父类做的扩展,NSMutableArray数组的元素可以动态的新增和删除,其他用法与NSArray一致。 所以: NSArray数组一旦创建,其元素的个数就固定,无法新增与删除 NSMutableArray数组,可以新增删除 3). NSMutableArray数组的创建NSMutableArray *arr1 = [NSMutableArray new]; NSMutableArray *arr2 = [[NSMutableArray alloc] init]; NSMutableArray *arr3 = [NSMutableArray array]; 这样创建出来的数组对象,数组的元素是0,但是有意义,可以动态的新增,删除. 最容易犯错:这样写不可以 NSMutableArray *arr1 = @[@"jack", @"rose", @"lili"]; 新增与删除 新增 a. // 将传入的参数作为数组的元素添加进去 - (void)addObject:(ObjectType)anObject; // 将另外一个数组中的每一个元素添加到可变数组中 - (void)addObjectsFromArray:(NSArray<ObjectType> *)otherArray;NSMutableArray *arr1 = [NSMutableArray new]; [arr1 addObject:@"jack"]; NSArray *arr = @[@"jack", @"rose", @"lili"]; [arr1 addObjectsFromArray:arr]; b. 在可变数组中指定的数组中插入一个元素 - (void)insertObject:(ObjectType)anObject atIndex:(NSUInteger)index;[arr insertObject:@"lilei", anIndex:1]; 删除 a. 删除 // 删除指定下标的元素 - (void) removeObjectAtIndex:(NSUInteger)index;NSMutableArray *arr1 = [NSMutableArray new]; [arr1 addObject:@"jack"]; NSArray *arr = @[@"jack", @"rose", @"lili"]; [arr1 addObjectsFromArray:arr]; [arr removeObjectAtIndex:1]; b. 删除特定的元素 - (void)removeObject:(ObjectType)anObject;NSMutableArray *arr1 = [NSMutableArray new]; [arr1 addObject:@"jack"]; NSArray *arr = @[@"jack", @"rose", @"lili"]; [arr1 addObjectsFromArray:arr]; [arr removeObject:@"lili"]; c. 删除指定范围内的元素 - (void)removeObject:(ObjectType)anObject inRange:(NSRange)range;NSMutableArray *arr1 = [NSMutableArray new]; [arr1 addObject:@"jack"]; NSArray *arr = @[@"jack", @"rose", @"lili"]; [arr1 addObjectsFromArray:arr]; [arr removeObject:@"lili" inRange:NSMakeRange(0, 3)]; d. 删除最后一个元素 - (void)removeLastObject;NSMutableArray *arr1 = [NSMutableArray new]; [arr1 addObject:@"jack"]; NSArray *arr = @[@"jack", @"rose", @"lili"]; [arr1 addObjectsFromArray:arr]; [arr removeLastObject]; e. 删除所有 - (void)removeAllObjects;NSMutableArray *arr1 = [NSMutableArray new]; [arr1 addObject:@"jack"]; NSArray *arr = @[@"jack", @"rose", @"lili"]; [arr1 addObjectsFromArray:arr]; [arr removeAllObjects]; NSNumber 1). 作用: 包装基本数据类型 NSNumber *number = [NSNumber numberWithInt:10]; 等价于 NSNumber *number = @10;

优秀的个人博客,低调大师

Objective-C 学习第十天

一、NSDictionary NSArray和NSMutableArray数组 存储数据特点:每个元素紧密相连,并且每个元素中都是直接存储的值. 缺点:数组元素下标不固定,都有可能发生变化,无法通过下标来唯一确定数组中的元素. NSDictionary(Key-Value存储)与NSMutableDictionary 1). 它们是数组,以键值对的形式存储数据,通过别名来找数据,类似于java中的Map集合. 2). 存储数据原理 a. 以键值对的形式存储数据 b. 字典数组一旦创建,其中的元素就无法动态的新增和删除 c. 键: 只能是遵守了NSCoping协议的对象,而NSString遵守了这个协议 值:只能是OC对象 3). 创建字典数组 NSDictionary *dict1 = [NSDictionary new]; NSDictionary *dict2 = [[NSDictionary alloc] init]; NSDictionary *dict3 = [NSDictionary dictionary]; 这种方式创建出来的字典数组没有任何元素,所以没有意义. 4). 一般创建方式 + (instancetype)dictionaryWithObjectsAndKeys:(id)firstObject... NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:@"jack", @"name",nil]; 将字典数组的值键依次写在后面初始化. 5). 简要创建方式 @{键1:值1,键2:值2...} NSDictionary *dict = @{@"name":@"rose",@"age":@"18"}; 6). 使用%@可以打印这个数组中所有的元素. 如果字典中没有键名,则返回nil. 1). 别名法 对象名[键名];NSDictionary *dict = @{@"name":@"rose",@"age":@"18"}; dict[@"name"]; 2). 方法 - (id)objectForKey:(id)aKey;NSDictionary *dict = @{@"name":@"rose",@"age":@"18"}; [dict objectForKey:@"name"]; 3). 取出键值对的个数 @property (readonly)NSUInteger count;NSDictionary *dict = @{@"name":@"rose",@"age":@"18"}; [dict count]; 遍历NSDictionary 1). 字典数组中的数据无法使用下标取 2). 使用for in 循环,遍历出来的是所有数组的键. NSDictionary *dict = @{@"name":@"rose",@"age":@"18"}; for(NSString *key : dict){ NSLog(@"%@ = %@", key, dict[key]); } 3). 使用block遍历 [dict enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop)]{ NSLog(@"%@ = %@", key, obj); } 4). 数据存储原理 a. 当往字典数组中存储一个键值对的时候,这个键值对应该存储在下标为几的元素中 ->> 并不是按照顺序挨个的存储的 ->> 存键值对的时候,会根据键值数组的长度做一个哈希算法,算出一个下标,将这个键值存储在该下标处 b. 取值 也是根据键做一个哈希算法,可以算出键值对存储的下标,然后直接找到这个下标的数据取出就可以了. 5). 与NSArray对比 a. NSArray数组的元素,挨个存,按着顺序 b. 存的效率,NSArray要高; 取的时候,单个取NSDictionary相对要快,全部取,NSArray快。 NSMutableDictionary 1). 是NSDictionary的子类 2). 创建可变字典数组 NSMutableDictionary *dict1 = [NSMutableDictionary new]; NSMutableDictionary *dict2 = [[NSMutableDictionary alloc] init]; NSMutableDictionary *dict3 = [NSMutableDictionary dictionary]; 这样创建处理的字典长度为0,有意义,可以动态的新增与删除. NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"jack", @"name",nil]; 创建的时候并且初始化. 注意: 不可以使用以下代码创建 NSMutableDictionary *dict = @{@"name":@"rose",@"age":@"18"}; 3). 新增键值对 NSMutableDictionary *dict1 = [NSMutableDictionary new]; [dict1 setObject:@"jack" forKey:@"name"]; 如果键名重复,则会覆盖. 4). 删除所有的键值对 - (void)removeAllObjects: 删除所有的键值对 - (void)removeObjectForKey:(KeyType)aKey;根据键名删除指定值 5). 持久化--保存到本地 写到本地 [dict writeToFile:@"/Users/Apple/Desktop/1.plist" atomically: NO]; 读到内存 [NSMutableDictionary dictionaryWithContentsOfFile:@"/Users/Apple/Desktop/1.plist"]; 集合的内存管理 将对象存储到集合之中,会为这个对象的引用计数器+1,当集合销毁的时候,就会像存储在集合中的所有的对象发送一条release消息. 使用@[]或者@{}创建的集合已经是被autorelease过的了. 直接调用对象方法和类方法创建的对象,也是autorelease过的. 在ARC模式下,集合的元素是一个强类型指针. 二、NSFileManager作用: 创建、删除、赋值、拷贝、移动 NSFileManager是以单例模式创建的 // 单例返回 NSFileManager *fileManager = [NSFileManager defaultManager]; 判断 1). 判断指定的文件或者文件夹在磁盘上是否真实的存在 - (BOOL)fileExistsAtPath:(NSString *)path; 2). 判断指定的路径是否真实的存储在我们的磁盘上,并且判断这个路径是一个文件夹还是一个路径 - (BOOL)fileExistsAtPath:(NSString *)path isDirectory:(BOOL *)isDirectory; 返回值: 代表这个路径是否真实存在 参数指针:代表这个路径是否是一个文件夹路径,YES为文件夹路径,NO为文件路径 3). 判断指定的文件夹或者文件是否可以读取 - (BOOL)isReadableFileAtPath:(NSString *)path; 4). 判断指定的文件夹或者文件是否可以写入. - (BOOL)isWritableFileAtPath:(NSString *)path; 5). 判断指定的文件夹或者文件是否可以删除 - (BOOL)isDeletableFileAtPath:(NSString *)path; 获取信息 1). 获取指定文件或者文件夹的属性信息 - (NSDictionary *)attributesOfItemAtPath:(NSString *)path error:(NSError **)error 返回是一个字典,如果要拿到特定的信息,通过key 2). 获取指定目录下的所有文件的目录,是拿到指定目录下的所有文件和目录,所有的后代目录和文件 - (NSArray *)subpathsAtPath:(NSString *)path; 3). 获取知道给你目录下的所有的子目录和文件,不保护孙子辈 - (NSArray *)contentsOfDirectoryAtPath:(NSString *)path error:(NSError **)error 文件/目录 1). 创建 - (BOOL)createFileAtPath:(NSString *)path contents:(NSData *)data attributes:(NSDictionary *)attr; 第1个参数: 要创建的文件路径 第2个参数: 文件的内容,NSData将别的数据转换为二进制数据 将字符串转换到NSData二进制的方式,调用字符串对象的 - (NSData *)dataUsingEncoding:(NSStringEncoding)encoding; 编码参数:NSUTF8StringEncoding 指定一个编码就可以将字符串转换为二进制数据,存储在NSData对象之中,最后再将这个二进制对象通过这个方法写入,如果想创建一个空文件,第2个参数就给nil。 第3个参数:指定创建的文件的属性,如果想要使用系统的默认值使用nil 2). 在指定的目录创建文件夹 - (BOOL)createDirectoryAtPath:(NSString *)path withIntermediateDirectories:(BOOL) createIntermediates attributes:(NSDictionary *)attributes error:(NSError **)error; 第1个参数:路径 第2个参数:YES,指一路创建,NO不做一路创建 第3个参数:指定属性,nil为系统默认 第4个参数:异常信息 3). 拷贝文件 - (BOOL) copyItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath error:(NSError **)error; 4). 移动文件,剪切,重命名 - (BOOL) moveItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath error:(NSError **)error; 5). 删除文件 - (BOOL) removeItemAtPath:(NSString *)path error:(NSError **)error; 注意: 删除的文件不会倒废纸篓,而是直接删除,小心使用 三、常用的结构体 CGPoint 1). Foundation框架中CGPoint定义 struct CGPoint{ CGFloat x; CGFloat y; }; typedef struct CGPoint CGPoint; typedef CGPoint NSPoint; CGPoint类型实际上就是一个double类型. 这个结构体一般情况下来表示坐标,用来表示控件上的位置 声明CGPoint变量并初始化的方式: a. CGPoint p1; p1.x = 20; p1.y = 30; b. CGPoint p1 = {20, 30}; c. CGPoint p1 = {.x=20,.y=30}; d. Foundation框架中提供的函数快速创建CGPoint a). CGPointMake(x,y) CGPoint p1 = CGPointMake(20,30); b). NSMakePoint(x,y) CGPoint p1 = NSMakePoint(20,30); CGSize 1). 用来描述控件的大小 struct CGSize{ CGFloat width; CGFloat height; }; typedef struct CGSize CGSize; typedef CGSize NSSize; CGSize结构体一般用来表示控件的大小 CGSize声明并初始化的方式 a. CGSize size; size.width = 100; size.height = 30; b. CGSize size = {100, 30}; c. CGSize size = {.width = 100, .height = 30}; d. Foundation框架中提供的函数快速创建CGSize a). CGSizeMake(x,y) CGSize s1 = CGSizeMake(20,30); b). NSSizePoint(x,y) NSSize s1 = NSMakeSize(20,30); CGRect 1). 用来描述控件的大小 struct CGRect{ CGPoint origin; CGSize size; }; typedef struct CGRect CGRect; typedef CGRect CGRect; CGRect结构体一般用来表示控件的大小 CGRect声明并初始化的方式 a. CGRect rect; rect.origin.x = 20; rect.origin.y = 30; rect.size.width = 100; rect.size.height = 30; b. CGRect rect; rect.origin = (CGPoint){100, 30}; rect.size = (CGSize){100, 30}; d. Foundation框架中提供的函数快速创建CGRect a). CGRectMake(x,y,width,height) CGRect s1 = CGRectMake(10,20,20,30); b). NSRectMake(x,y,width,height) NSReca s1 = NSRectMake(10,20,20,30); 建议使用CG开头的 四、NSValue NSRange/CGPoint/CGSize/CGRect都是结构体,无法存储到集合中 先将结构体变量存储到OC对象中,在将OC对象存储到集合中 NSValue类的对象就是用来包装结构体变量的 CGPoint p1 = CGPointMake(10,20); NSValue *v1 = [NSValue valueWithPoint:p1]; 五、NSDate 时间处理 创建NSDate时间 NSDate *date = [NSDate new]; NSDate *date = [NSDate date]; 格式化输出日期 yyyy 代表年份 MM 代表月份 dd 代表日 HH 代表24小时制,hh代表12小时制 mm 代表分钟 ss 代表秒 NSDate *date = [NSDate new]; // 1. 先创建日期格式化对象,输出一个指定格式的对象 NSDateFormatter *formatter = [NSDateFormatter new]; // 2. 指定日期格式化对象 转换的格式 formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss"; // 3. 格式化对象按照指定的格式将日期对象转换,转换的时候会自动的转换为当前系统的时区 NSString *str = [formatter stringFromDate:date]; NSString *strDate = @"2011-12-12 12:12:12"; // 1. 先创建一个日期格式化器对象 NSDateFormatter *formatter = [NSDateFormatter new]; // 2. 指定字符串日期的格式 formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss"; // 3. 转换 NSDate *date = [formatter dateFromString:strDate]; 计算时间 1). 当前时间之上加上一个时间数 + (instancetype)dateWithTimeIntervalSinceNow:(NSTimeInterval)secs; ``` NSDate *date = [NSDate new]; NSDate *date1 = [NSDate dateWithTimeIntervalSinceNow:60*60*10]; ``` 2). 两个时间之差 - (NSTimeInterval)timeIntervalSinceDate:(NSDate *)anotherDate; 日历对象 NSDate *date = [NSDate date]; // 1. 创建一个日历对象 NSCalendar *calendar = [NSCalendar currentCalendar]; // 2. 让日历对象从日期对象取出日期的各个部分 NSDateComponents *com = [calendar components: NSCalendarUnitYear fromDate:date]; com.year,com.month,com.day 六、copy 无论是MRC还是ARC下,如果属性的类型是NSString类型的,@property参数使用copy. copy是个方法 1). 定义在NSObject中,作用:拷贝对象 NSString 调用copy方法,没有产生新对象,而是直接将对象本身的地址返回去,这种拷贝我们叫做浅拷贝. NSMutableString调用copy对象,产生了一个新对象,这种拷贝叫做深拷贝。拷贝出的对象是一个不可变的字符串对象。 2). mutableCopy拷贝之后是一个NSMutableString,是一个可变对象 字符串拷贝计数器问题 1). 若字符串对象存储在常量区中不允许被回收的,所以引用计数器是一个超大的数,retain和release无效 2). 若字符串存储在对去,这个字符串对象和普通的对象是一样的,引用计数器默认是1. 3). 字符串对象如果是浅拷贝,会将对象的引用计数器加1. 字符串对象如果是深拷贝,原来的对象的引用计数器不变. @property的copy copy方法的内部调用了另外一个方法copyWithZone方法,这个方法是定义在NSCoping协议中的,因为我们类没有遵守NSCopingWithZone方法,当我们自定义的类调用copy方法就会报错。 copyWithZone方法实现 --> 如果要做深拷贝,即重新创建一个对象,把对象属性的值复制到新对象中,将新对象返回。 --> 如果做浅拷贝,就直接将对象返回即可. 七、单例模式 一个类的对象,无论在什么时候,什么地方创建,得到的对象都是同一个.最终都会调用该alloc方法创建. 1). alloc方法的内部其实什么都没有做,只是调用了allocWithZone方法. 2). 实际上真正申请空间,创建对象的事情是allocWithZone方法在做. 要实现单例模式--重写+allocWithZone方法 + (instancetype)allocWithZone:(struct _NSZone *)zone{ static id instance = nil; if(nil == instance){ instance = [super allocWithZone:zone]; } return instance; } 单例规范 如果类是一个单例模式,要求为类提供一个类方法,来返回这个单例对象。 类方法的名称必须以 shared类名; default类名; 什么时候要把类写成单例的 1). 特点: 一个类的对象,无论在什么时候,什么地方创建,得到的对象都是同一个.最终都会调用该alloc方法创建.存储在单例对象中的数据可以被共享.

优秀的个人博客,低调大师

Objective-C 学习第五天

一、 创建一个对象,内存是如何分配 1). 子类对象中有自己的属性和所有父类的属性 2). 代码段中每一个类都有一个isa指针,这个指针指向它的父类. 结构体与类 相同点: 都可以将多个数据封装为1个整体 struct Data{ int year; int month; int day; } @interface Data : NSObject{ int year; int month; int day; } 2). 不同点: a. 结构体只能封装数据,而类不仅可以封装数据还可以封装行为 b. 结构体变量分配在栈空间(前提是局部变量),而对象分配在堆空间. 栈空间相对较小,但是访问效率高; 堆空间较大, 访问效率低. 3). 应用场景: a. 如果表示的实体不仅有数据还有行为,只能使用类 b. 如果表示的实体只有数据, 没有行为,视属性多少而定.如果属性只有几个,就定义为结构体; 如果属性较多,就定义为类. 类的本质 栈 堆 BSS段 数据段 代码段 内存.png 代码段是用来存储代码的. 类加载,当类第一次被访问的时候,这个类就会被加载到代码段存储起来. 类一旦被加载,是不会被回收的,除非程序结束. 1). 任何存储在内存中的数据都有1个数据类型. 2). 在代码段存储类的步骤 a. 先在代码段中创建Class对象, Class是Foundation框架中的一个类 b. 将类的信息存储在这个Class对象之中 Class对象至少有三个属性: 类名/属性s/方法s 存储类的这个Class对象,叫做类对象 所以存储类的类对象也有一个isa指针 类对象使用 1). 调用类的类方法class,就可以了得到存储类的类对象的地址 Class c1 = [Person class]; 2). 调用对象的对象方法,就可以了得到这个对象所属的类的Class对象的地址. Person p1 = [Person new]; Class c2 = [p1 class]; 注意: 声明Class指针的时候,不需要加,因为typedef的时候就已经加*了. 3). 拿到存储类的类对象以后 Class c1 = [Person class]; c1对象就是Person类, c1 完全等价于Person a. 使用类对象来调用类的类方法, Class c1 = [Person class]; [c1 sayHi] 等价于 [Person sayHi]; b. 创建对象 Class c1 = [Person class]; [c1 new] 等价于 [Person new]; 注意: 使用类对象,只能调用类的类方法,不能调用对象方法 SEL全程 select 选择器 SEL是一个数据类型. 要在内存中申请空间存储数据,SEL其实是一个类,SEL对象用来存储一个方法 1). 类是以Class对象的形式存储在代码段中 类名: 存储这个类的类名.NSString a. 如何将方法存储在类对象之中 a). 先创建一个SEL对象 b). 将方法的信息存储在这个SEL对象之中 c). 再将这个SEL作为Class对象的属性 2). 拿到存储方法的SEL对象 a. 因为SEL是typedef类型的,在自定义的时候已经加了,所以声明SEL指针的时候不需要加 b. 取到存储方法的SEL对象 SEL s1 = @selector(方法名); 示例: SEL s1 = @selector(sayHi); 3). 调用方法的本质 Person p1 = [Person new]; [p1 sayHi]; 内部原理: a. 先拿到存储sayHi方法的SEL对象,也就是拿到sayHi方法的SEL数据,SEL消息 b. 将这个SEL消息发送给p1对象 c. p1对象接收到这个SEL消息之后,就知道调用方法 d. 根据对象的isa指针找到存储类的类对象 e. 如果找到这个类对象之后,搜寻是否有和传入的SEL数据相匹配的,如果有,就执行,如果乜有就找父类,知道NSObject OC最重要的1个机制: 消息机制 调用方法的本质其实就是为对象发送SEL消息 [p1 sayHi]: 为p1对象发送一个sayHi方法 4). 手动为对象发送SEL消息 a. 先得到方法的SEL数据 b. 把这个SEL数据发送给p1对象 - (id)performSelector:(SEL)aSelector; 示例:Person *p1 = [Person new]; SEL s1 = @selector(sayHi); [p1 performSelector:sel]; c. 调用一个对象的方法有两种 a). [对象名 方法名]; b). 手动的为对象发送SEL消息 5). 注意事项: a. 如果方法名有参数 那么方法名是带了参数的 b. 如果方法有参数,就调用另外一个方法 - (id)performSelector:(SEL)aSelector withObject:(id)object; c. 如果方法有多个参数,就将对象传递过去 点语法 OC中也可以使用点语法来访问对象的属性,和Java,C#是完全不一样的. 1). 使用点语法访问对象的属性. 语法:对象名.去掉下划线的属性名p1.name = @"jack";这个时候就会将@"jack"赋值给p1对象的_name属性; NSString *name = p1.name;把p1对象的_name属性值取出来 2). 点语法原理 p1.age = 18; 这句话的本质并不是把18直接赋值给p1对象的_age属性,点语法在编译器编译的时候,会将点语法转换为调用setter/getter的代码 a. 当使用点语法赋值的时候,这个时候编译器会将点语法转换为调用setter方法的代码. 对象名.去掉下划线的属性名 = 数据; 转换为: [对象名 set去掉下划线的属性名首字母大写] = 数据; p1.age = 10相当于[p1 setAge:10]; b. 当使用点语法取值的时候,这个时候编译器会将点语法转换为调用getter方法的代码. 对象名.去掉下划线的属性名; 转换为: [对象名 去掉下划线的属性名]; int age = p1.ag相当于[p1 age]; 3). 注意: a. 在getter/setter方法中慎用点语法, 因为有可能会造成无线递归导致程序崩溃 b. 点语法在编译器编译的时候会转换为setter/getter方法的代码. 如果我们的setter和getter方法名不符合规范,那么就会报错. c. 如果属性没有封装getter/setter是无法使用点语法的 @property 1). 写一个类 a. 写属性 b. 声明属性的getter/setter c. 再实现getter/setter 2). @property a. 作用: 自动生成getter/setter的声明,应该写在@interface声明之中 b. 语法: @property 数据类型 变量名; @property int age; c. 原理: 编译器在编译的时候,会根据@property生成getter/setter方法的实现 @property 数据类型 名称; 生成为: - (void)set首字母大写的名称:参数; - (数据类型)名称; 示例: @property int age; - (void)setAge:(int)age; - (int)age; 3). 使用@property注意: a. @property的类型和属性的类型一致. @property的名称和属性名称一致(去掉下划线). b. @property的名称决定了生成getter和setter方法的名称. @property的数据类型决定了生成的getter和setter方法的数据类型. c. @property只是生成getter和setter方法的声明,实现要自己写. @synthesize 1). 作用: 自动生成getter/setter方法的实现,应该写在类的实现当中 2). 语法: @synthesize @property名称; // 声明 @interface Person : NSObject{ int _age; } @property int age; @end; // 实现 @implementation Person @synthesize age; @end 3). @synthesize做的事情 a. 生成一个真私有的属性,属性的类型和@synthesize对应的@property类型一致,属性的名字和@synthesize对应的@property名字一致. b. 自动生成setter方法的实现 实现的方式:将参数直接赋值给自动生成的那个私有属性.并且没有做任何的逻辑验证 c. 自动生成getter方法的实现 4). 希望@synthesize不要自动生成私有属性,getter/setter的实现中操作我们写好的属性. a. 语法 @synthesize @property 名称 = 已经存在的属性名; 示例: @synthesiez age = _age; a). 不会再生成私有属性 b). 直接生成getter/setter的实现. setter实现: 把参数的值直接赋值给指定的属性. getter的实现: 直接返回指定的属性的值. 5). 注意: a. 如果直接写一个@synthesize @synthesize name; b. 如果指定操作的属性. @synthesize name = _name; c. 生成的setter方法实现中没有任何逻辑验证,生成的getter方法的实现中式直接返回属性的值 d. 如果要有自己的逻辑验证,需要自己实现. 6). 批量声明 a. 如果多个@property的类型一致,可以批量声明. @property float height,weight; b. @synthesize批量写, @synthesize name = _name, age = _age; @property增强 1). 从4.4之后, 对@property做了增强. 2). 只需要写一个@property,编译器就会自动的生成私有属性、生成getter/setter的声明、生成getter/setter的实现. 3). @property NSString *name; a. 自动的生成一个私有属性, 属性的类型和@property类型一致,属性的名称和@property的名称一致,属性的名称自动的加下划线 b. 自动的生成getter/setter的声明 c. 自动的生成getter/setter的实现 setter的实现直接将参数的值赋值给自动生成的私有属性. getter的实现直接返回私有属性的值. 4). 使用注意 a. @property的类型一定要和属性的类型一致,名称要和属性的名称一致 b. 可以批量声明 动态类型和静态类型 1). OC是一门若语言,编译器在编译的时候,检查的时候没有那么严格. 优点:灵活 缺点:太灵活 强类型的语言: 编译器在编译的时候做语言检查的时候,非常严格. 2). a. 静态类型:指的是一个指针指向的对象是一个本类对象, b. 动态类型: 指的是一个指针指向的对象不是本类对象。 3). 编译检查:编译器在编译的时候,能不能通过1个指针去调用指针指向的对象的方法. 判断原则:看这个指针所属的类型之中是否有这个方法,如果有就认为可以调用,编译通过,如果没有就报错。 4). 运行检查: 编译检查只是骗过了编译器,但是这个方法究竟能不能执行还不一定,运行时会去检查对象当中是否有这个方法 NSObject是OC中所有类的基类,根据LSP NSObject指针就可以指向任意的OC对象,所有NSObject指针时一个万能指针.可以指向任意的OC对象. 缺点: 如果要调用指向的子类对象的独有的方法,就必须要就类型的强转。 id指针是一个万能指针,可以指向任意的OC对象. 1). id是一个typedef类型,在定义的时候已经加了,所以声明id指针的时候就不需要加了 2). id指针是一个万能指针,任意的OC对象都可以指。 3). NSObject与id 相同点: 万能指针,都可以指向任意的OC对象 不同点: 通过NSObject指针去调用对象的方法的时候,编译器会做编译检查.通过id类型的指针去调用对象方法的时候,不会报错. 4). 注意:id指针只能调用方法,不能使用点语法 instancetype 1). 如果方法的返回值是instancetype代表方法的返回值是当前类的对象.// 声明 - (instancetype)person; // 实现 - (instancetype)person{ return [self new]; } 建议: a. 如果方法内部是在创建当前类的对象,不要写死成类名[类名 new],而是用self代替类名 b. 如果方法的返回值是当前类的对象,也不要写死了,而是写instancetype. 2). id和instancetype的区别 a. instancetype只能作为方法的返回值,不能在其他地方使用,id既可以声明指针变量也可以作为参数,也可以作为返回值 b. instancetype是一个有类型的代表当前类的对象,id是一个无类型的指针,仅仅是一个地址,没有类型的指针 构造方法 1). 创建对象 类名 *指针名 = [类名 new]; new 实际上是个类方法. new方法作用: -> 创建对象 -> 初始化对象 -> 把对象的地址返回 new方法的内部,其实是先调用alloc方法,再调用init方法 alloc方法是一个类方法,那个类调用这个方法就创建哪个类对象 init是一个对象方法,初始化对象 创建对象的完整步骤: 应该是先使用alloc创建一个对象,然后使用init初始化这个对象 Person *p1 = [Person new]; 完全等价于 Person *p1 = [[Person alloc] init]; 2). init方法 作用: 初始化对象,为对象的属性赋初始值,这个init方法我们叫做构造方法 init方法做到的事情: 初始化对象. 3). 想要让创建对象的属性的默认值不是nil,NULL,0,那么我们可以重写init方法.按照我们自己的想法为对象的属性赋值. 重写init方法规范: a. 必须先调用父类的init方法. b. 调用方法初始化对象失败返回nil c. 判断父类是否初始化成功,如果不是nil,说明初始化成功 d. 如果初始化成功,就初始化当前对象的属性 e. 最后返回self - (instancetype)init{ // 初始化父类属性的值 self = [super init]; if(self){ self.name = @"jack"; } return self; } 4). 自定义构造方法 规范: a. 返回值必须是instancetype b. 自定义构造方法开头必须是initWith c. 方法的实现与init的要求一样 - (instancetype)initWithName:(NSString *)name{ // 初始化父类属性的值 self = [super init]; if(self){ self.name = name; } return self; } Dog *d1 = [[Dog alloc] initWithName:@"小黄"]; 动态类型检测 1). 判断指针指向的对象当中,指定的方法是否可以调用 Person *p1 = [Person new]; BOOL isHave = [p1 responseToSelector:@selector(setName:)]; 2). 判断类方法是否可以调用 3). 判断对象是否为指定类对象或者子类对象 NSMutableString *str = [NSMutableString class]; BOOL res = [str isKindOfClass:[NSString class]]; 4). 判断对象是否为指定类的对象(不包括子类) NSMutableString *str = [NSMutableString class]; BOOL res = [str isMemberOfClass:[NSString class]]; 5). 判断指定的类是否为另外一个类的子类 BOOL res = [NSMutableString isSubclassOfClass:[NSString class]];

优秀的个人博客,低调大师

Objective-C 学习第七天

一、 自动释放池的原理 存入到自动释放池中的对象,在自动释放池销毁的时候,会自动调用储存在该自动释放池中的所有对象的release方法. 可以解决的问题: 将创建的对象,存入到自动释放池之中,就不再需要手动的release这个对象了,因为池子销毁的时候,就会自动的调用池中所有的对象release. 如何创建自动释放池 @autoreleasepool{ } 这对大括号代表这个自动释放池的范围 如何将对象存储到这个自动释放池中 在自动释放池之中调用对象的autoreleasepool方法,就会将这个对象存入到当前自动释放池之中,这个autorelease方法返回的是对象本身,所以可以这么写 @autoreleasepool{ Person *p1 = [[[Person alloc] init] autorelease]; } 这个时候,当这个自动释放池执行完毕之后,就会立即为这个自动释放池中的对象发送一条release消息. autorelease好处: 创建对象,调用对象的autorelease方法,将这个对象存入当前的自动释放池之中,我们不需要再去release,因为自动释放池销毁的时候,就会自动的调用池中所有对象的release. 使用注意 1). 只有在自动释放池中调用了对象的autorelease方法,这个对象才会被存储到这个自动释放池中,如果只是将创建对象的代码写在自动释放池中,而没有调用对象的autorelease方法,是不会将这个对象存储到这个自动释放池之中的. 2). 对象的创建可以在自动释放池的外面,在自动释放池中,调用对象的autorelease方法,就可以将这个对象存储到这个自动释放池中. 3). 如果对象的autorelease方法的调用放在自动释放池的外面,是无法将其存储到这个自动释放池之中的,autorelease的调用只有放在自动释放池之中,才可以将其存储到自动释放池之中,对象的创建可以在外面. 4). 当自动释放池结束的时候,仅仅是对存储在自动释放池中的对象发送一条release消息,而不是销毁对象. 5). 如果在自动释放池中,调用同一个对象的autorelease方法多次,就会将这个对象存储多次到这个自动释放池中,在自动释放池结束的时候,就会为对象发送多次release消息. 所以,一个自动释放池中,只autorelease一次,只讲这个对象放一次,否则就会出现野指针错误. 6). 如果在自动释放池中,调用了存储到自动释放池中的对象的release方法,在自动释放池结束的时候,还会再调用对象的release方法,这个时候也有可能会造成野指针操作. 7). 将对象存储到自动释放池,并不会使对象的引用计数器+1,其好处就是创建对象存储早自动释放池,就不要再写release方法了. 8). 自动释放池可以嵌套.调用对象的autorelease方法,只会讲对象加入到自动释放池中,只有在当前自动释放池结束的时候才会向对象发送release消息. autorelease规范 1). 创建对象,将对象存储到自动释放池中,就不需要再去手动的release 2). 类方法的第一个规范: 一般情况下,要求提供与自定义构造方法相同功能的类方法,这样可以快速的创建一个对象. 3). 类方法的第二个规范: 一般情况下,会为我们的类写一个类方法,用来让外界调用类方法类快速的得到一个对象. 规范: 使用类方法创建的对象,要求这个对象已经被autorelease过了. 提供一个类方法来快速的得到一个对象. 规范: a. 这个类方法已类名开头,如果没有参数就直接是类名,如果有参数就是withXX: b. 使用类方法得到的对象,要求这个对象已经被autorelease过了 + (instancetype)person{ return [[[selft alloc] init] autorelease]; } 这样我们直接调用类方法,就可以得到一个已经被autorelease过的对象. @autoreleasepoop{ Person *p1 = [Person person]; // 这个p1对象已经被autorelease过了,不需要再调用autorelease方法 // 这个对象被存储到当前的自动释放池中 }// 当自动释放池结束,就会为存储在其中的p1对象发送release消息. 二、ARC 什么是ARC Automatic Reference Counting 自动引用计数,即ARC 顾名思义: 系统自动的帮助我们去计算对象的应用计数器的值. 在程序中使用ARC非常简单,只需要像往常一样编写代码. 只不过永远不要写retain、release、autorelease这三个关键字就好,这个ARC最基本的原则. 当ARC开启时,编译器会自动的在合适的地方插入retain、release、autorelease代码,编译器自动为对象做引用计数,而作为开发者,完全不需要担心编译器会做错. 需要特别注意: ARC是编译器机制,在编译器编译代码的时候,会在适当的位置加入retain、release、autorelease代码. 在ARC机制下,对象何时被释放: 只要没有强指针指向这个对象,这个对象就会立即回收. 强指针与弱指针 强指针: 默认情况下,我们声明一个指针,这个指针就是强指针,我们也可以使用__strong来显示的声明这是一个强指针. Person *p1; 这是一个强指针,指针默认情况下都是一个强指针. __strong Person *p2; 这也是一个强指针,使用__strong来显示声明的强指针. 弱指针: 使用__weak标识的指针就叫做弱指针. 无论强指针还是弱指针,都是指针,都可以用来存储地址,都可以通过这个指针访问对象的成员,唯一的区别就是在ARC模式下,他们用来作为回收对象的基准. 确认程序是否开启ARC机制 1). 默认情况下,Xcode开启ARC机制 2). ARC机制下,不允许调用retain/release/retainCount/autorelease方法 3). 在dealloc中不允许[super dealloc] 演示第一个ARC案例 int main(int argc, const char *argv[]){ @autoreleasepool{ Person *p1 = [Person new]; }// 当执行到这里,p1指针被回收 return 0; } ARC下的单个对象的内存管理 在ARC机制下: 当没有任何一个强指针指向它的时候,就会被立即回收. 1). 当指向对象的所有的强指针被回收的时候,对象就会被立即回收 int main(int argc, const char *argv[]){ @autoreleasepool{ Person *p1 = [Person new]; Person *p2 = p1; }// 当执行到这里,p1指针被回收,p2指针也被回收 return 0; } 2). 将所有指向对象的强指针赋值为nil的时候,对象就会被立即回收 int main(int argc, const char *argv[]){ @autoreleasepool{ Person *p1 = [Person new]; p1 = nil; }// 当执行到这里,p1指针被回收,p2指针也被回收 return 0; } 强指针与弱指针 1). 强指针与弱指针的声明 默认情况下,所有的指针都是强类型的. Person *p1 = [[Person alloc] init]; p1指针是强类型的,因为默认情况下指针都是强类型的. 不过我们可以使用__strong来显示的标识指针是强类型指针. __strong Person *p2 = [Person new]; 这时候p2指针是强类型的,其实写不写__strong都是强类型指针. 指针类型也可以是弱指针类型. 使用__weak标识指针的类型是弱类型指针. __weak Person *p3 = p2; 这时候,p3指针是1个弱类型的指针,p3弱指针也指向p2强指针指向的对象. 在操作对象的时候,通过强指针或者弱指针都可以操作,没有任何区别 2). ARC模式下的对象回收标准 ARC机制下释放对象的标准,没有任何强指针指向对象的时候,对象就会被释放.如果这个时候有弱指针指向,也会被释放。 int main(int argc, const char *argv[]){ @autoreleasepool{ __strong Person *p1 = [[Person alloc] init]; __weak Person *p2 = p1; p1 = nil;// 当执行到这里,p1指针被回收,p2指针也被回收 } return 0; } 3). 最重要的一点:不能创建对象用1个弱指针存储这个对象的指针,这样的话,刚创建出来的对象,就没有任何强指针指向,创建处理就会被回收. int main(int argc, const char *argv[]){ @autoreleasepool{ // 创建一个对象,刚创建出来就会被回收 __weak Person *p2 = [[Person alloc] init]; } return 0; } 4). 在ARC的机制下,原来指向这个对象的弱指针,会被自动设置为nil. 在ARC机制下,@property参数就不能使用retain,因为retain代表生成的setter方法是MRC的标准的内存管理代码,而我们在ARC机制下不需要那些代码. 所以在ARC机制下的setter方法,什么都不需要做. ARC机制下,关注的重点,当一个类的属性是一个OC对象的时候,这个属性应该声明为强类型的. 1). 控制@property生成的私有属性,是一个强类型还是弱类型. 使用参数strong和weak @property(nonatomic,strong)Car *car; 代表生成的_car是强类型 @property(nonatomic,weak)Car *car; 代表生成的_car是弱类型 如果不写,默认是strong 使用建议 1). 在ARC机制下,如果属性的类型是OC对象类型,使用strong 2). 在ARC机制下,如果属性的类型不是OC对象类型,使用assign 3). strong和weak都是应用在属性类型是OC对象的时候 4). 在ARC机制下,将MRC下的retain换为strong 循环引用 解决方案: 其中一方使用weak,另一方使用strong 三、 遇到的问题--MRC与ARC兼容 点击项目->Target->Build Phases->Compile Sources->选中要使用MRC编译的类,双击->填写 -fno-objc-arc 使用命令-fno-objc-arc MRC转换为ARC Edit-> Convert->To Object-C ARC...->选中要转成ARC的程序选中,点击Check->Next->Save. 分类(类别/类目)--category 默认情况一个类独占一个模块,这个时候将所有的成员都写在这个模块中,很难管理。将功能相似的方法定义在同一个模块中,这样的好处,方便维护和管理。 1). 顾名思义: 把类分开,将一个类分为多个模块 2). 如何为一个类添加分类: Target->New File->Objective-C File->Next, File: itcast File Type: Category Class: Student(选择要分的类) Next->Create. 3). 会生成一个.h和一个.m模块 a. 模块的文件名是本类名+分类名.h,本类名+分类名.m 4). 添加的分类分为声明和实现 @interface 本类名 (分类名) @end 代表不是新创建一个类,而是对已有的类添加一个分类,小括弧中写上分类的名字,因为一个类可以添加多个分类,为了区分每个类 @implementation 本类名 (分类名) @end 这是分类的实现 5). 分类的使用 a. 如果要访问分类中定义的成员,就要把分类的头文件引进来. 6). 分类的作用:就是将一个类分为多个模块 7). 注意 a. 分类中只能增加方法,不能增加属性 b. 在分类中可以写@property但是不会自动 生成私有属性,也不会自动生成getter/setter的实现,只会生成getter/setter的声明 c. 在分类的方法实现中不可以直接访问本类的私有属性,但是可以调用本类的getter/setter来访问属性 d. 当分类中有和本类同名方法的时候,优先调用分类的方法,哪怕没有引入分类的头文件,如果多个分类中有多个相同的方法,优先调用最后编译的分类 8). 什么时候需要使用分类 当一个类的方法很多很杂的时候,比较臃肿的时候,这个时候就可以使用分类,将功能相似的方法写在同一个模块当中 分类的作用在于可以将我们写的类分为多个模块 为系统自带的类写分类,这就叫做非正式协议. 1). 分类的第一个作用: 分为多个模块,方便管理 2). 分类的第二个作用: 为一个已经存在的类添加方法

优秀的个人博客,低调大师

Objective-C 学习第一天

一、基础语法 OC相对于C a. 在C的基础上新增了面向对象的语言 b. 将C的复杂、繁琐的语法封装的更为简单 c. OC完全兼容C语言 OC程序的源文件后缀名是.m m代表message 代表OC当中最重要的一个机制 消息机制 C程序的源文件的后缀名.c main函数仍然是OC程序的入口和出口 int类型的返回值代表程序的结束状态 main函数的参数: 仍然可以接收用户在运行程序的时候传递数据给程序, 参数也可以不要 #import指令 1). 以#号开头,是1个预处理指令 2). 作用: 是#include指令的增强版。将文件的内容在预编译的时候拷贝在写指令的地方 3). 增强: 同一个文件无论#import多少次,只会包含一次 如果#include指令要实现这个效果,就必须要配合条件编译指令来实现 而#import指令只需要直接包含就可以 4). 简要原理: #import指令在包含文件的时候,底层会先判断这个文件是否被包含, 如果被包含就会被略过,否则才会包含。 框架 1). 是一个功能集 苹果或者第三方事先将一些程序在开发程序时经常要用到的功能事先写好 把这些功能封装在一个类或函数中,这些函数和类的集合就叫做框架。 有点像C语言的函数库 2). Foundation框架 Foundation: 基础 基本. 这个框架当中提供了一些最基本的功能 输入输出, 数据类型 Foundation.h 这个文件当中包含了Foundation包含了其他所有的头文件 只要包含Foundation.h就想当于包含了框架当中所有的头文件。 @autoreleasepool{} 自动释放池 代码写在这个大括号中 NSLog函数 1). 作用: 是printf函数的增强版, 向控制台输出信息 2). 语法: NSLog(@"格式控制字符串", 变量列表); 最简单语法: NSLog(@"要输出的信息"); 3). 增强: a. 输出一些调试相关的信息 2020-07-01 12:40:05.175 Day01-OC基础用法 [792:213878] Hello,World 执行代码的时间 程序名称 792是进程编号,213878是线程编号 输出信息 可用于测试程序执行时间 b. 会自动换行 c. OC新增的数据类型的变量的值只能使用NSLog函数输出 4). 用法和printf函数差不多 5). 使用注意: a. NSLog函数的第一个参数前面必须要加1个@符号 b. 如果在字符串的末尾加1个'\n'代表换行, 那么函数的自动换行会失效 字符串 1). C语言的字符串的存储方式 a. 使用字符数组存储 b. 使用字符指针 2). OC当中更为好用的存储字符串的类型. NSString NSString类型的指针变量专门用来存储OC字符串的地址 3). OC的字符串必须要使用1个前缀@符号 "jack" 是一个C语言的字符串 @"jack" 是一个OC的字符串常量 NSString 类型的指针变量只能存储OC字符串的地址 4). 使用 NSString *str = @"jack"; 5). 总结 a. 在OC中专门设计了1个NSString类型来存储字符串 b. 字符串分为C字符串和OC字符串 c. 区分: 是否有@前缀 6). 注意 a. NSLog函数的第1个参数是OC字符串 b. 输出 NSString *str = @"jack"; NSLog(str); c. 如果要使用NSLog函数中的占位符输出字符串的值, 应使用"%@" NS前缀 NextStep --> Cocoa --> Foundation框架之中 @符号 1). 将C字符串转换为OC字符串 "jack" ->> @"jack" 2). OC当中的绝大部分关键字是以@符号开头 注释: 和C语言的注释一模一样, 分为单行注释和多行注释 函数的定义和调用: 与C语言的函数调用是一样的 void test();// 声明 void test(){// 实现 } 二、OC与C的对比 OC程序的编译、链接、执行 1). 在.m文件中写上符合OC程序的源代码 2). 使用编译器将源代码编译为目标文件 cc -c xx.m a. 预处理 b. 检查语法 c. 编译 3). 链接 cc xx.o 如果程序中使用到了框架中的函数或者类,那么在链接时就必须要告诉编译器去哪里找Foundation框架 cc xx.o -framework Foundation 4). 链接成功后, 就会生成1个a.out可执行文件, 使用"./a.out"执行 OC程序和C程序各个阶段的后缀名对比 源文件 目标文件 可执行文件 C .m .o .out OC .m .o .out OC中的数据类型 1). OC中支持C语言中的所有的数据类型 a. 基本数据类型 int double float char b. 构造类型 数组 结构体 枚举 c. 指针类型 d. 空类型 e. typedef自定义类型 2). BOOL 类型 BOOL b1; a. 可以存储YES或者NO中的任意1个数据(必须是大写). b. 一般情况下BOOL类型的变量用来存储条件表达式的结果. c. BOOL的本质 typedef signed char BOOL; 实际上BOOL类型的变量是1个有符号的char变量 #define YES ((BOOL)1) #define NO ((BOOL)0) 4). Boolean a. Boolean类型的变量可以存储true或者false b. 一般情况下BOOL类型的变量用来存储条件表达式的结果. c. 本质 typedef unsigned char Boolean; #define true 1 #define false 0 5). class 类型. 类 6). id 类型 万能指针. 7). nil 与 null 差不多 8). SEL 方法选择器 9). block 代码段 三、 面向过程与面向对象 OC是在C的基础之上 1). 将C复杂的语法封装的更为简单 2). 在C语言的基础之上新增了一小部分的面向对象的语法 实现需求之一: 1). 要把大象放进冰箱应该怎么办? a. 打开冰箱门 b. 把冰箱放进去 c. 把冰箱门关上 2). 买电脑的需求的实现方式: a. 根据自己的需求和预算确定买的电脑型号 10000 iOS开发 b. 在网上查资料 确定型号 rMMP 9288 c. 去到数码产品中心 d. 找到Apple专卖店 e. 砍价 成交 f. 回家 3). 更好的方式: a. 自己做 强调的是过程, 步骤. 我是主角 b. 别人做 强调的比人. 我是指挥者 面向过程: 如果解决1件事情的时候,每一件事情都是我们亲自去一步步实现 面向对象: 如果解决1件事情的时候,自己不去做,而是专门找一个人去做 代码世界的面向过程与面向对象. 1). 面向过程 在遇到1个需求的时候,每个步骤都是自己亲自写代码完成 2). 面向对象 在遇到1个需求的时候,而是找一个专门做这件事的人 面向对象和面向过程优缺点 C语言是一门面向过程的语言. 有功能的概念, 但是没有人的概念. OC语言是一门面向对象的语言. 面向过程解决问题的缺点: 后期维护和修改不方便. 面向对象解决问题的优点: 后期维护和修改方便. 如何使用面向对象设计程序 当遇到一个需求的时候,不要亲自去实现. 1). 先看看有没有现成的框架做这件事 2). 如果没有,就自己实现 对象: 现实生活中的一个具体存在, 看得见、摸得着,拿过来可以直接使用 类: 是对一群具有相同特征或者行为的事物的统称.抽象的,不能直接使用. 类和对象之间的关系 四、 类与对象 请问先有类还是先有对象 1). 现实角度 一定是先有对象再有类 2). 代码角度 一定是先有类再有对象 类的作用: 描述一群具有相同特征和行为的事物 如何定义类 1). 类的三要素: 类名/特征/行为 2). 定义类的语法 a. 位置. 直接写在源文件中 b. 类的定义分为两部分 --> 类的声明 @interface 类名 : NSObject { 这类事物具有的共同特征, 将他们定义为变量 } 功能就是方法,将声明写在这里 @end --> 类的实现 @implementation 类名 将方法的实现写在这里 @end 3). 注意 a. 类必须要有声明和实现 b. 类名用你描述事物的名称来命名. 类名的每个单词单词首字母必须要大写. c. 用来表示这类事物共同特征的变量必须要定义在@interface中的大括号中 d. 定义在大括号用来表示类事物共同特征的变量叫属性、成员变量、实例变量、字段... e. 属性名必须要以下划线开头 示例: // 声明 @interface Person : NSObject { NSString *_name; int _age; float _height; } @end // 实现 @implementation Person @end 类是无法直接使用的. 如果非要使用这个类,必须要先找到这个类的具体存在 1). 如何创建一个类的对象 语法: 类名 *对象名 = [类名 new]; Person *p1 = [Person new];//创建Person对象 p1对象的特点: ->> 可以直接使用 ->> 类定定义的东西, 对象都有 如何使用对象 1). 如何访问对象的属性: a. 默认情况下,对象的属型是不允许被外界直接访问的 如果允许对象的属性可以被外界访问,声明属性时加@public关键字 b. 访问对象的属性的方式 对象名->属性名 = 值; 对象名->属性名; (对象名).属性名 = 值; (对象名).属性名 示例: // 声明 @interface Person : NSObject { @public NSString *_name; int _age; float _height; } @end // 实现 @implementation Person @end // 使用-- 平时建议使用这种形式 Person *p1 = [Person new]; p1->_name = @"jack"; p1->_age = 19; p1->_height = 178.5f; NSLog(@"p1对象的_name属性的值是%@", p1->_name); (*p1)._name = @"jack"; (*p1)._age = 19; (*p1)._height = 178.5f; 方法的声明和调用 // 声明 @interface Person : NSObject { 属性: 类的特征 } 方法: 类的功能 @end // 实现 @implementation Person 方法实现 @end 无参数方法声明 1). 声明 a. 位置: 在@interface的大括号的外面 b. 语法: - (返回值类型) 方法名称; - (void)run; 表示声明了1个无返回值的并且无参数的方法, 名字叫run 2). 实现 a. 位置: 在@implementation之中实现 b. 语法: 将方法声明拷贝到@implementation中,去掉分号追加大括号 3). 调用 a. 方法是无法直接调用的, 必须要创建对象 b. 调用对象的方法. [对象名 方法名]; 示例: // 声明 @interface Person : NSObject{ NSString *_name; int _age; } - (void)run; @end // 实现 @implementation Person - (void)run{ NSLog(@"Hello,World!"); } @end // 调用 Person *p1 = [Person new]; [p1 run]; 带1个参数的方法 1). 声明 a. 位置: 在@interface的大括号的外面 b. 语法: - (返回值类型) 方法名称:(参数的类型)形参名称; - (void)eat:(NSString *)foodName; 表示声明了1个无返回值的含有一个参数的方法, 名字叫"eat:",有一个参数类型是NSString *类型,参数的名字叫foodName 2). 实现 a. 位置: 在@implementation之中实现 b. 语法: 将方法声明拷贝到@implementation中,去掉分号追加大括号 3). 调用 a. 方法是无法直接调用的, 必须要创建对象 b. 调用对象的方法. [对象名 方法名:实参]; 示例: // 声明 @interface Person : NSObject{ NSString *_name; int _age; } - (void)run; - (void)eat:(NSString *)foodName; @end // 实现 @implementation Person - (void)run{ NSLog(@"Hello,World!"); } - (void)eat:(NSString *)foodName{ NSLog(@"给我的%@真好吃",foodName); } @end // 调用 Person *p1 = [Person new]; [p1 run]; [p1 eat:@"红烧排骨"]; 方法头中的数据类型都要用1个小括号括起来. (返回值类型)方法名称:(参数类型)参数名称; 带多个参数的方法 1). 声明 a. 位置: 在@interface的大括号的外面 b. 语法: - (返回值类型) 方法名称:(参数的类型)参数名称1 :(参数类型)参数名称2.。。; - (int)sum:(int)num1 :(int)num2; 表示声明了1个返回值为int的含有两个参数的方法, 名字叫"sum: :",有两个参数 参数类型都是int类型, 参数名称叫做num1,num2 2). 实现 a. 位置: 在@implementation之中实现 b. 语法: 将方法声明拷贝到@implementation中,去掉分号追加大括号 3). 调用 a. 方法是无法直接调用的, 必须要创建对象 b. 调用对象的方法. [对象名 方法名:实参1 :实参2]; 示例: // 声明 @interface Person : NSObject{ NSString *_name; int _age; } - (void)run; - (void)eat:(NSString *)foodName; - (int)sum:(int)num1 :(int)num2; @end // 实现 @implementation Person - (void)run{ NSLog(@"Hello,World!"); } - (void)eat:(NSString *)foodName{ NSLog(@"给我的%@真好吃",foodName); } - (int)sum:(int)num1 :(int)num2{ int num3 = num1 + num2; return num3; } @end // 调用 Person *p1 = [Person new]; [p1 run]; [p1 eat:@"红烧排骨"]; int sum = [p1 sum:10 :20]; NSLog(@"sum = %d",sum); 带参数的方法声明的规范:--提高阅读性. 1). 如果方法只有1个参数: 要去最好这个方法的名字叫做xxxWith: - (void)eatWithFood:(NSString *)foodName; 2). 如果方法有多个参数: 方法名With: (参数类型)参数名称1 and:(参数类型)参数名称2; - (int)sum:(int)num1 and:(int)num2; 3). 更详细的写法 方法名With参数1:(参数类型)参数名称1 and参数2:(参数类型)参数名称2... 其他使用注意 1). 快捷 a. 快速实现方法: - -> 空格 方法名 b. 快速创建对象: 对象 new -> 右括号(自动补齐)

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册