1. ** mac os认识 :
dmg: 把xx.apk拖到应用程序中
pkg: 双击就可以安装
2. ** C和OC对比:
1. c 头.h,实现.c co 头.h 实现.m, 多文件开发语言属于
2. c的关键字都可以在oc中使用,oc新增关键字使用@开头
3. 数据类型添加了 布尔类型等等
4. 流程控制: oc添加了增强for
** 创建一个可以写c 和 oc 的 工程使用xcode:
创建一个macOS Command Line Tool程序, 可以写oc/c程序的控制台
3.头文件导入,打印
Include : 在当前文件、开发工具、系统找
编译器、系统找
#import foundation/foundaton.h
NSLog(@"hello -oc")
4. OC中类语法
4.1 OC中类定义
@interface 类名首字母大写
属性前面添加一个_
{
@public int _age;
}
// 方法必须依赖于类,不能独立,c中的函数可以独立属于整个文件
-(void)about; //对象方法,void是数据类型,oc中()用来括住数据类型
-(int)loadMsg; // 有返回值,没有参数
-(int)loadMsg2 :(int)arg1 :(int)arg2; // 必须在参数数据类型前面添加:,方法名loadMsg2::
-(int)loadMsg2 :(int)arg1 SecondArgs:(int)arg2; // 为了提高阅读性,可以在参数前面添加说明,方法名loadMsg2:SecondArgs:
+ // 类方法
@end
** 类的实现
@implementation 类名
-(void)about{
NSLog(@“实现方法”);
}
-(int)loadMsg{
return 10;
}
-(int)loadMsg2 :(int)arg1 :(int)arg2{
return arg1+arg2;
}
@end
** 类创建对象:
类* p=[类 new]; // 在堆中申请内存
p->_age=20; // 调用属性
[p about] //调用对象about方法
int ii=[p loagMsg];
int add=[p loadMsg2:3:4];
4.2. Objective-C 中类属性的封装:
类的成员变量,在类的内部,在{}内部,理论上外界不能被访问,只能通过get|set方法访问
.h 声明:
@interface book : NSObject
{
// 类的成员属性
int _age;
}
- (void)setAge:(int)_age;
-(int)getAge;
@end
.m实现:
@implementation book
-(void) setAge:(int)age{
_age=age;
}
-(int) getAge{
return _age;
}
@end
调用:
book* b1=[book new];
[b1 setAge:2000];
NSLog(@"--%d---",[b1 getAge]);
4.3. 点语法:如果给属性添加了getter、setter语法,那么 对象.属性来访问
使用 : p.age =10 相当于setter方法
p.age 相当于getter方法
4.4. OC中的self关键字:
[self 类方法/对象方法]:
注意: self 在对象中表示对象,不可以调用类方法
self 在类方法中表示类,不可以调用对象方法
谁调用这个方法,在方法内部self就表示谁
4.5. 继承使用:
[ super ] : 子类重写中调用父类的方法
OC 中的多态:
Animal* a1= [Dog new]: OC和Java一样的,都是调用子类
功能: 参数传递 + (void)food:(Animal*) a
[(Dog*)a1 bark]: 如果要调用子类特有方法,强制转换为子类
description: 重写,相当于java 的toString()
4.6. OC 中访问修饰符
@public:
@private:
属性、和方法只在.m中实现,不在头文件中声明,那么就是私有的
@protected: 不可以在其他类中访问,可以在子类访问,默认是protected
@package:
当前包所有可以访问
其他包不可以访问
注意: 直接写在.m中的类的成员变量是默认私有变量
5. Property 类快速封装,在头文件中
功能: 写上@property自动替换getter、setter方法
book.h 中使用
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface book : NSObject
// 属性修饰符, 只有getter方法
@property(readonly) int age;
@property NSString* name;
// boolean类型 getter方法修改为 isXXX,可读这样
@property(getter=isMarried) bool marreid;
@end
NS_ASSUME_NONNULL_END
注意: 1.如果想过滤数据,自己手动写getter、setter方法
6. id和instancetype都是万能指针:
// 动态类型, alloc 申请堆内存 , init 构造方法
id obj= [[book alloc] init];
// 判断指定的对象是否是某一个类,或者某一个类的子类
// 运行时候真实类型不符合条件,报错
if( [obj isKindOfClass:[book class]]){
[obj showMsg2];
}
// 判断某一个对象是否是当前指定类的实例
if([obj isMemberOfClass:[book class]]){
[obj showMsg2];
}
id和instancetype都是万能指针:
id 在编译的时候不能判断对象的真实类型,可以定义变量,可以做返回值,形参
instancetype: 在编译的的时候可以判断对象真实类型,只能够做返回值(init返回)
7. 构造方法
8. 自定义类工厂方法,苹果的规范
======== book.h ==================================
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface book : NSObject
// 属性修饰符, 只有getter方法
//@property(readonly) int age;
@property int age;
@property NSString* name;
// boolean类型 getter方法修改为 isXXX,可读这样
@property(getter=isMarried) bool marreid;
-(instancetype)initWithAge:(int)age andName:(NSString*)name;
// 自定义 类工厂方法, 用于快速创建对象
+(instancetype)book1;
// 带参数
+(instancetype)bookWithAge:(int)age andName:(NSString*)name;
@end
NS_ASSUME_NONNULL_END
==========================================
book.m 实现:
//
#import "book.h"
@implementation book
// init 构造方法初始化变量
- (instancetype)init
{
// 判断是否初始化成功
// 为什么要 [super init] ,子类必须要初始化父类的属性,否则报错
self = [super init];
if (self) {
_age=2000;
}
return self;
}
// 带参数的构造方法
-(instancetype)initWithAge:(int)age andName:(NSString*)name{
self = [super init];
if(self){
_age=age;
_name=name;
}
return self;
}
// 类工厂方法实现,用于快速创建对象
+(instancetype)book1{
book* b1= [[self alloc] init];
return b1;
}
+(instancetype)bookWithAge:(int)age andName:(NSString*)name{
// 这里使用self,避免在子类中继承出问题
book* b1= [[self alloc] init];
b1.age=age;
b1.name=name;
return b1;
}
@end
===========================================
main方法调用:
// 调用自定义构造方法
//book* b2= [[ book alloc] initWithAge:30 andName:@"小明"];
// 调用类工厂方法
book* b3= [book book1];
NSLog(@"====%d",b3.age);
// 调用类 带参数的类工厂方法
book* b4= [book bookWithAge:30 andName:@"xiaoming"];
NSLog(@"====%d====%@",b4.age,b4.name);
// 苹果规范,比如NString、NSArray,方便其他人使用
// alloc init
[[NSString alloc] init];
// 带参数的构造函数
[[NSString alloc] initWithString:@"hello"];
// 类工厂方法
[NSString stringWithString:@"hello"];
xcode10 自定义代码块实现setter、getter方法 ??
9. 字符串
// 字符串创建第一种方式
NSString* str=@“abc”; //把c字符串转换为oc字符串,字符串对象存储在常量区
NSString* str2=@“abc”;
// 如果字符串常量内容一致,那么存储位置相同,str和str2指向 同一块内存
NSLog(@“content=%@“,str); //输出 oc 字符串
// 字符串的格式化: 字符串存储在堆区,第二种方式
NSString *str = [NSString stringWithFormat:@"age = %i, height = %f\n", 30, 1.75];
// 字符串创建第三种方式
NSString* str3= [[NSString alloc] initWithFormat:@"hello"];
NSLog(@"str3--%@",str3);
// 字符串创建第四种方式
NSString* str4= [[NSString alloc] initWithString:@"hello2"];
NSLog(@"str4--%@",str4);
字符串的长度:
NSUInteger len = [str length]; //NSUInteger就是 unsign int
NSLog(@"len = %lu", len);
字符串其他操作: 字符串读写文件、字符串比较
// 从文件中读取字符串
NSString* path=@"/Users/denganzhi/aa.java";
NSError* error=nil;
NSString* str1=[NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error];
if(error == nil){
NSLog(@"---%@---",str1);
}else{
NSLog(@"-error--%@---",[error localizedDescription]);
}
// 字符串写入文件中
// atomically yes: 字符串写入过程中没有写完,不会生成文件
// NO, 字符串写入过程中没有写完,会生成文件
NSString* str2=@"xiaoming";
[str2 writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:nil];
// 协议头
// http:// 网络资源 file:// 本地资源
// NSURL* url1= [NSURL URLWithString:@"file:///Users/denganzhi/aa.java"];
// 通过fileURLWithPath,方法创建url,系统会自动给我传入的url添加协议头file://
// url 不支持中文路径,但是通过fileurlpath可以支持中文路径
NSURL* url1= [NSURL fileURLWithPath:@"/Users/denganzhi/aa.java"];
NSString* str4= [NSString stringWithContentsOfURL:url1 encoding:NSUTF8StringEncoding error:nil];
NSLog(@"---str4=%@",str4);
// 写入
// 后面的内容会覆盖前面的内容
// [str4 writeToURL:<#(nonnull NSURL *)#> atomically:<#(BOOL)#> encoding:<#(NSStringEncoding)#> error:<#(NSError *__autoreleasing _Nullable * _Nullable)#>]
// 字符串比较
NSString* str5=@"hello";
NSString* str6=@"hell2";
// 比较内容是否相同
BOOL flag= [str5 isEqualToString:str6];
NSLog(@"flag==%i",flag);
// 比较地址是否相同
BOOL flag2= (str5 == str6) ;
NSLog(@"flag2==%i",flag2);
NSComparisonResult result = [str5 compare:str6];
if(result==NSOrderedAscending){
NSLog(@"前面的小于后面的");
}else if(result == NSOrderedSame){
NSLog(@"字符串相等");
}else if(result == NSOrderedDescending){
NSLog(@"前面的大于后面的");
}
10. 字符串 包含
11. 字符串截取
12. 字符串替换
13. 字符串和路径 , 还有很多函数可以百度
14. 字符字符 转化
// 10. 字符串 包含
NSString* str=@"http://www.baidu.com";
// 以 什么开头
BOOL b1= [str hasPrefix:@"http"];
//以 什么结果
BOOL b2= [str hasSuffix:@".com"];
NSLog(@"b1--%i--b2--%i",b1,b2);
NSRange range= [str rangeOfString:@"www"];
// 匹配从哪个字符开始 匹配长度
NSLog(@"location=%lu,length=%lu",range.location,range.length);
// 11. 字符串截取
// 字符串截取, 从第2个位置开始截取,截取5个字符
NSRange range1= NSMakeRange(2, 5);
NSString* newStr= [str substringWithRange:range1];
NSLog(@"--newStr:%@",newStr);
//12. 字符串替换
NSString* replaceStr= [str stringByReplacingOccurrencesOfString:@"//" withString:@"&&"];
NSLog(@"replaceStr=%@",replaceStr);
// 去除收尾空格
NSString* str12=@" http://sina.com ";
NSCharacterSet* set= [NSCharacterSet whitespaceCharacterSet];
NSString* newStr12= [str12 stringByTrimmingCharactersInSet:set];
NSLog(@"--newStr12==%@",newStr12);
// 13. 字符串和路径 , 还有很多函数可以百度
NSString* str13=@"/Users/denganzhi/Desktop/Tophotoart.zip";
NSString* newStr13_1 = [str13 lastPathComponent];
// 获取字符串的最后一个目录,Tophotoart.zip
NSLog(@"--newStr13_1=%@",newStr13_1);
// 14. 字符字符 转化
NSLog(@"--%@--",[str13 uppercaseString]);
// 字符串于基本数据类型转化
NSString* str14=@"110";
// 如果转化失败,那么结果是0
int value= [str14 intValue];
// c字符串 转化为 oc 字符串
char* ch="xiaozhi";
NSString* str14_1= [NSString stringWithUTF8String:ch];
NSLog(@"---%@---",str14_1);
//NString 转化为 char*
const char* ch2= [str14_1 UTF8String];
NSLog(@"--ch2--%s",ch2);
可变字符串:
// insert code here...
// 1.不可变字符串,str1首先执行"abx",然后str1 执行”def"
// 如果对字符串频繁操作使用可变字符串,避免浪费内存
NSLog(@"Hello, World!");
NSString* str1= @"abc";
str1= @"def";
// 2. 可变字符串
NSMutableString* str3=[NSMutableString string];
[str3 appendFormat:@"abc is %i",10];
[str3 appendString:@" def"];
NSLog(@"str3=%@",str3);
NSMutableString* str4= [NSMutableString stringWithFormat:@"http://it.520.com"];
// 3. 首先查找字符串
NSRange range= [str4 rangeOfString:@"520"];
// 4. 删除指定字符串
[str4 deleteCharactersInRange:range];
NSLog(@"--str4=%@",str4);
// 5. 插入在.com前面
NSUInteger range1=[str4 rangeOfString:@".com"].location;
[str4 insertString:@"kaitou" atIndex:range1];
// 6. 字符串替换,不会修改原来的字符串,返回新字符串
NSString* newStr= [str4 stringByReplacingOccurrencesOfString:@"com" withString:@"vip"];
// 7. 替换所有内容
NSMutableString* str5= [NSMutableString stringWithFormat:@"http://it.520.com,520"];
// 返回替换的个数
// options: 替换时候的搜索方式,从前替换,或者从后替换
NSUInteger count = [str5 replaceOccurrencesOfString:@"520" withString:@"vip" options:0 range: NSMakeRange(0, str5.length)];
NSLog(@"--str5_1=%lu",count);
10. .h和.m 切换: command+ ctrl+ 上
如何快速查看文档: 按住option键+点击对应类
11. 类的启动原理:
+ (void)load{ }:
只会调用一次,类被加载到内存中调用
如果有父类,首先调用父类load,在调用子类load
+ (void)initialize {} :
只会调用一次,即使new多个对象,类使用的时候调用
用途: 单例
如果有父类,首先调动父类initialize,在调用子类initialize
*** SEI存储类方法的签名,通过签名调用方法
// 11.1. 判断方法是否存在
// 类中是否存在 - 对象方法
SEL sel = @selector(setName:);
BOOL flag= [b4 respondsToSelector:sel];
if(flag){
// [b4 performSelector:sel]; //没有参数
// 通过sel 调用方法,方法的参数必须是 对象类型
// 最多只能传递2个参数
// [b4 performSelector:sel withObject:@"xiaoming" withObject:@"xiaohei"];
[b4 performSelector:sel withObject:@"xiaoming"];
NSLog(@"--name =%@==",b4.name);
}
NSLog(@"flag1===%i",flag); // 输出1
// 11.2. 判断是否存在 + 类方法
BOOL flag2= [book respondsToSelector:@selector(load)];
NSLog(@"flag2===%i",flag2);
12. Objective-C MRC、ARC:
OC 堆内存管理, alloc init 以后, 要release
如果存在引用: 解决方法,引用计数
例子:
但是如果 B类 中有 A类对象,A使用完毕,直接 释放A 类对象以后显然不行
引用计数:
new A的时候A 对象计数是1, 如果B 引用了A类, 那么A 类计数+1(retain)
A 类释放堆内存此时,引用计数 减1(release), A类 应用计数不为0,A 类在堆中,不被释放
如果B 类释放, B类中的A对象 被释放
此时,引用计数为0 , 那么 A 的堆内存释放
OC对应api:
alloc init ---- release
retain: 计数器+1
release: 计数器-1
retainCount: 返回当前引用计数个数,不准确
什么时候会触发引用计数:
类依赖、类放入集合、copy、 block 中引用对象(会进行copy)、计数都要retain加1
Objective-C 自动内存释放:
OC 中引入了autorelease
** 什么是 autorelease:
autorelease: 自动释放池,是一种支持引用计数的内存管理方式,只要给对象发送一条 autorelease消息,
会将对象放到一个自动释放池中,当自动释放池被销毁时,会对池子里 面所有对象做一次 release操作
OC中的类都实现了 autorelease
cocos2d-x内存管理方式也是autorelease,c++
ARC: 编译特性,xcode 给你补全了 自动释放内存代码
13. 使用:@property
@property(nonatomic, retain) Room *room; // 避免内存泄露
readonly: 只会生成getter方法
getter: 给getter方法起一个名词
setter: 给setter方法起一个名词
默认基本数据类型: 默认,assign只会生成getter|setter方法
实体类: retain,自动生成内存管理代码
字符串: copy
nonatomic,reation,getter=isVip
// 多线程
automic: 性能低(默认),原子性
nonatomic: 性能高,一般用这个
14. @class使用
.h: 写@class,
为什么不使用 #import在头文件中,
// #import 是一个预编译指令, 他会将”“中的文件拷贝到import的位置,编译效率变低
// @class 不做任何拷贝,只是声明
.m: 写#import
写法.h中: @class Wheel;
.m中: #import "Wheel.h"
15. Category (分类)
功能: 不修改原来的类的基础上给类添加方法,也可以用继承
创建一个通过模板category, new->Objective-C File->选项category
注意点:
1. 分类只能够给原有类添加方法,不能添加属性
2. 可以在分类中访问原有类.h的属性
NSString+MyNString.h 头文件
#import <AppKit/AppKit.h>
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/**
// className: 需要给哪个类扩充方法
/ / categoryName: 分类的名称
@ interface ClassName(categoryName)
// 扩充的方法名
NewMethod
*/
@interface NSString (MyNString)
+(void)showStr;
// 统计字符串中中文数字,方法1
// int count= [NSString countWithtStr:str];
+(int) countWithtStr:(NSString*)str;
// 方法2
// int count= [str countWidthStr2];
-(int) countWidthStr2;
@end
NS_ASSUME_NONNULL_END
NSString+MyNString.m 头文件实现
#import "NSString+MyNString.h"
#import <AppKit/AppKit.h>
@implementation NSString (MyNString)
+(void)showStr{
NSLog(@"showStr----");
}
+(int) countWithtStr:(NSString*)str{
// NSString* str=@"2233kkjjjj";
int count=0;
for (int i=0; i<str.length; i++) {
//这里返回的是unichar 不是char
// unichar 可以包含任意ascII码值
unichar c= [str characterAtIndex:i];
if(c>= '0' && c<='9'){
count++;
}
}
return count;
}
-(int) countWidthStr2{
int count=0;
// self 表示调用字符串
for (int i=0; i<self.length; i++) {
//这里返回的是unichar 不是char
// unichar 可以包含任意ascII码值
unichar c= [self characterAtIndex:i];
if(c>= '0' && c<='9'){
count++;
}
}
return count;
}
@end
main.m 调用方法
#import <Foundation/Foundation.h>
// 这里必须要引入分类
#import "NSString+MyNString.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
// 调用分类方法
[NSString showStr];
NSString* str=@"2233kkjjjj";
// int count=0;
// for (int i=0; i<str.length; i++) {
// //这里返回的是unichar 不是char
// // unichar 可以包含任意ascII码值
// unichar c= [str characterAtIndex:i];
// if(c>= '0' && c<='9'){
// count++;
// }
// }
// 调用1
// int count= [NSString countWithtStr:str];
// 使用self 封装, 调用2
int count= [str countWidthStr2];
NSLog(@"count=%d",count);
}
return 0;
}
16. 匿名分类:
在.m中添加:给类扩充私有属性、方法
Person.h 头文件
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface Person : NSObject
@end
NS_ASSUME_NONNULL_END
Person.m 实现
#import "Person.h"
// 在.m中添加:给类扩充私有属性、方法
// 匿名分类
// 分类和匿名分类区别:
// 分类中有名称,匿名分类中没有
// 匿名分类可以扩充属性
@interface Person()
{
int _age;
}
-(void) sayAge;
@end
@implementation Person
@end
17. 代码块
1. block使用
// roseBlock是一个变量值
int (^roseBlock) (int num);
// block 的语句块
roseBlock=^(int num){ // 或者:int (^roseBlock) (int num)=^(int num){}
NSLog(@"我是block对象,参数是:%d",num);
return num;
};
// 语法类型:
// block变量 = ^(int num)[参数]{ //代码块 }
// 调用block 代码块
int avg= roseBlock(400);
NSLog(@"该数据是:%d",avg);
2.使用typeof:
typedef int (^roseBlock) (int num); // roleBlock 是一个变量
roseBlock r= ^(int num){}
3. block可以 访问{}外部 变量,但是不可以修改(block用到外部变量,
会拷贝一份,如果是对象拷贝以后存储在堆中,会对对象进行retain操作,存在释放问题)
__block int avg=50
如果一定要修改,添加__block, 外界也会改变,block在栈中,不会retain
如果访问外界对象,一定要加_ _, 避免内存泄露
18. 协议Protocol 类似于Java中接口
在oc中一个类可以遵守多个协议
但是是单继承
通过xcode模板创建一个protocol, new->Objective-C File->选项protocol
协议方法:
@requied -(void) playBall; ,默认就是 @required,不实现该方法会爆警告⚠️
@optional : 可选的,可以实现,可以不实现,如果是@required,那么会报警告
头文件中实现协议:
@interface Student: NSObject< A 协议, B 协议>
@end
*** NSObject就是一个 所有类协议统一的协议