[BS] 小知识点总结-04
1. ios新知识学习思路:
在开发过程中如果遇到某种新需求以前从未做过,例如改变textField的Placeholder颜色,有如下思路和途径:
1.1 在Storyboard/Xib辅助编辑器Attributes inspector查找是否有相关设置。
1.2 查看UITextField.h头文件,查找是否有相关属性、方法、遵从的协议、代理的方法。
1.3 去父类UIControl.h中,查找是否有相关属性、方法、遵从的协议、代理的方法。
1.4 使用Baidu/Google搜索,论坛Stack Overflow等,或者去开发QQ/微信群求助;
1.5 使用runtime或者打断点Breakpoint查看UItextField类中所有的实例变量,通过KVC设值。
1.6 使用runtime或者Breakpoint找到相关实例变量,自定义继承UITextField类,重新设置属性值。
2.
凡是不可变类的对象(如NSString,富文本NSAttibuteString,NSArray,NSDictionary等),在创建时就必须存入内容,之后不可变对象存在于堆内存中,再也不能对其进行修改了。非要修改,只能将原来的销毁,然后重新创建一个新的不可变对象。
3.
NSMutableAttributedString(富文本: 颜色/大小/样式丰富多彩)用法
NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc]initWithString:@"这是一串五颜六色的文字" attributes:@{NSForegroundColorAttributeName:[UIColor whiteColor]}];
self.phoneTextField.attributedPlaceholder = attrString;
哪些常见的控件可以设置富文本属性呢?
A. textField.attributedPlaceholder = attrString;
B. 所有的UILabel*lbl; 都可以设置富文本lbl.attributedText = attrString;
C. 字符串可以通过绘图方法 [str drawInRect: withAttributes:] 和 str drawAtPoint: withAttributes:
4.
对于苹果封装好的标准UI控件,如果想要调整其内部子控件的布局,需要新建子类,然后在子类.m中重写layoutSubviews方法。
5.
苹果封装好的类,只要在其头文件中暴露出来的属性/方法,都可以新建子类对其进行自定义。对于未暴露出来的内部私有属性,可以通过Runtime/或运行时打断点获取,然后通过自定义子类来修改。
6.
ios开发中常用的纯C语言库有:Core Foundation/GCD/Runtime, 都是纯C语言,ARC只对OC有效,所以使用C语言,必须自己管理内存。
C语言中malloc, calloc, realloc, new, copy出来的指针指向的内存空间,使用完均需使用free(p)进行释放,并让p=Null,防止野指针
运行时(Runtime): 是苹果官方的一套纯C语言库。可以做很多底层的操作,如查看类的所有成员变量(包含私有的),属性,方法,协议等。
- (void)viewDidLoad {
[super viewDidLoad]; unsigned int count1 = ;
Ivar *p; //定义Ivar类型的指针p,指向装着实例变量的数组
p = class_copyIvarList([UITextField class], &count1); //返回的是一个Ivar类型的数组的指针(首地址),就像 Ivan a[count1];中存储的都是Ivar类型,然后让指针p = a; for (int i = ; i < count1; i++) {
//p指向Ivar类型的数组,使用Ivar类型变量取出
Ivar var = *(p+i);
//Ivar类的getName方法, C语言字符串使用%s
NSLog(@"%s", ivar_getName(var));
} //C语言自己管理内存copy
free(p);
p = NULL; //防止也指针 }
7.
在类的内部,通过self调用的方法只能是类方法,不能调用内部的对象方法。因为在类方法中self代表着本类。self在对象方法中代表当前类的对象。
8.
如下方法可以获取info.plist中的key-value:
NSString *currentVersion = [NSBundle mainBundle].infoDictionary[@"CFBundleShortVersionString"]; //本次打开应用的版本
应用启动后一般会有多个window,他们存在单例[UIApplication sharedApplication].windows数组中,通过如下方法可获取keyWindow
UIWindow *window = [UIApplication sharedApplication].keyWindow;
9.
数组/字典的addObject:方法的参数都不能为nil,因为数组/字典是以nil作为结尾的。[UIImage imageNamed:str];的str也不能为nil,否则直接崩溃。
一劳永逸的解决方案:可以用runtime交换方法(Method Swizzle “ios黑魔法”)实现的思路,对以上方法进行拦截,然后对传入的对象做判断,如果为nil,就不添加。
10.
NSString、NSArray、NSDictionary、NSData可以将数据直接写入本地文件中(文件格式随意写,只是用来告诉系统用什么软件打开)
//发送请求
[[AFHTTPSessionManager manager] GET:@"http://www.badung.com.php" parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
//先将id改为NSDictionary*类型, 将服务器返回数据写入本地plist文件
[(NSDictionary *)responseObject writeToFile:@"/Users/wz/Desktop/Words.plist" atomically:YES]; } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { }];
NSData *data = [[NSData alloc]init];
[data writeToFile:@"/Users/wz/Desktop/data.arc" atomically:YES];
NSString *string = [[NSString alloc]init];
[string writeToFile:@"/Users/wz/Desktop/string.text" atomically:YES encoding:NSUTF8StringEncoding error:nil];
NSArray *array = @[@"123",@"456",@"789"];
[array writeToFile:@"/Users/wz/Desktop/array.text" atomically:YES];
11.
写第三方框架的人为什么很多方法需要带个前缀?如sd_setImageWithURL: , mj_footer等。
答案: sd_setImageWithURL:方法是定义在#import “UIImageView+WebCache.h”中,一般给系统提供的框架类建分类时,可能会重写系统类原有的方法,因为分类的优先级高于原类,这样就会将原来的方法覆盖掉,如有想用原来方法时就没法调用了。为了区别分类和原类中方法,所以在给系统类增加分类时,分类中方法一般会带前缀。
补11. 减少不稳定的第三方框架的风险:
//此处做法是为了减少不稳定的第三方框架的风险。通过自定义类继承自第三方框架,我们应用内部全部导入自定义类的头文件,并使用我们重写过的方法,这样如果哪天不想用DA这个框架,想换成M13框架,只需要在自定义这个类中将继承的父类换为M13即可。我们App内部的所有头文件和方法名都不会报错,也不用去修改。
@interface WZTopicPictureProgressView : DALabeledCircularProgressView
@end
12.
a&b和a&&b运算结果相同,但a&&b效率更高。一旦发现a的值为false,就停止运算,直接得出结果为false。只有当a为true,才会计算b的值。
a|b和a||b运算结果相同,但a||b效率更高。一旦发现a的值为true,就停止运算,直接得出结果为true。只有当a为false,才会计算b的值。
13. UTC 和 GMT的区别是什么啊?
GMT:格林尼治标准时间Greenwich Mean Time(也称universal time),是指位于伦敦郊区的皇家格林尼治天文台的标准时间,因为在通过那里的经线被定义本初子午线。地球每天的自转是有些不规则的,而且正在缓慢减速。所以,格林尼治时间已经不再被作为标准时间使用。
UTC:协调世界时Coordinated Universal Time由原子钟提供,是现在全世界的标准时间。这套时间系统被应用于许多互联网和万维网的标准中,例如,网络时间协议就是协调世界时在互联网中使用的一种方式。中国大陆、中国香港、中国澳门、中国台湾、蒙古国、新加坡、马来西亚、菲律宾、西澳大利亚州的时间与UTC的时差均为+8,也就是UTC+8。
使用Xcode打印【NSDate date】时间与实际相差8个小时解决方案:
- (void)printDate: (NSDate *)date {
NSTimeZone *zone = [NSTimeZone systemTimeZone];
NSInteger interval = [zone secondsFromGMTForDate: date];
NSDate *localDate = [date dateByAddingTimeInterval: interval];
NSLog(@"\n date:%@\nlocalDate:%@",date,localDate);
}
14.
- (NSDateComponents *)components:(NSCalendarUnit)unitFlags
fromDate:(NSDate *)startingDate
toDate:(NSDate *)resultDate
options:(NSCalendarOptions)options
The resulting component values may be negative if resultDate(小) is before startDate(大). //如果resultDate小,startDate大,就会出现负值。
可见以上方法,从fromDate 到 toDate,是用toDate减去fromDate.
15.
不直接在tableView代理方法heightForRowAtIndexPath中计算cell高度的原因:
1. heightForRowAtIndexPath方法和cellForRowAtIndexPath方法的调用频率一样,当一个Row滚出屏幕再次滚回屏幕,就需要调用这两个方法。将计算cell高度的代码放在这里,同一Row每次出现时都要计算一次需要的cell高度。这样比较浪费。可以在模型中新增rowHeight属性(模型本来就代表需要展示的Row),在cellHeight属性的get方法通过懒加载将计算出来的Row需要Cell高度存放在模型的_cellHeight实例变量中。这样可以保证每个Row(模型)只计算一次cell高度。
2. Cell的高度虽然是tableView的属性,但是真正的高度是由model中的文字/图片等内容的数量/字体等决定的,当模型中加载完数据,其实就可以将该模型(Row)展示时需要的cell的高度计算好,并存储在模型(Row)的cellHeight属性中。需要展示该模型时,直接通过model.cellHeight取出所需cell的高度即可。
eg1. 在代理方法heightForRowAtIndexPath中计算cell高度
#pragma mark - Table view delegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { //获取模型,根据模型文字来计算Label的高度
WZTopic *topic = self.topics[indexPath.row];
//计算模型文字块高度
//[topic.text sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:14]}].height; //只能计算一横行文字的长度
//[topic.text sizeWithFont:[UIFont systemFontOfSize:14] constrainedToSize:CGSizeMake([UIScreen mainScreen].bounds.size.width, MAXFLOAT)].height;//提示ios7已弃用,使用boundingRectWithSize方法
CGFloat textH = [topic.text boundingRectWithSize:CGSizeMake([UIScreen mainScreen].bounds.size.width - 4 *WZTopicCellMargin, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:14]} context:nil].size.height; //计算并返回cell(只有文字时)高度
//CGFloat cellH = WZTopicCellTextY + textH +WZTopicCellBottomBarH;//此处算好的cellH,会被WZTopicCell.m中的setFrame拦截,并将高度减去一个margin,故此处需故意多加个margin抵消减去,才能让cell中的内容都完全显示出来,否则text将有一个margin的高度显示在底部工具条上。
//CGFloat cellH = WZTopicCellTextY + textH +WZTopicCellBottomBarH + WZTopicCellMargin; //刚刚好,紧贴底部工具条最上边
CGFloat cellH = WZTopicCellTextY + textH +WZTopicCellBottomBarH + WZTopicCellMargin + WZTopicCellMargin; //文字下边缘与底部工具条最上边留一个margin return cellH;
}
eg2.在模型(需要展示的Row)的cellHeight属性中计算cell高度
//WZModel.h文件
@property (assign,nonatomic) CGFloat cellHeight; //WZModel.m文件
- (CGFloat)cellHeight { if (_cellHeight == ) { //模型第一次展示时==0,需要计算,否则直接返回 //计算模型文字块高度
CGFloat textH = [self.text boundingRectWithSize:CGSizeMake([UIScreen mainScreen].bounds.size.width - *WZTopicCellMargin, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:]} context:nil].size.height; //计算cell(只有文字时)高度
_cellHeight = WZTopicCellTextY + textH +WZTopicCellBottomBarH + WZTopicCellMargin + WZTopicCellMargin;
} return _cellHeight; //第二次/第三次展示,直接返回cell高度
} #pragma mark - Table view delegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { //获取模型
WZTopic *topic = self.topics[indexPath.row]; //返回模型中算好的cell高度
return topic.cellHeight; }
16.
(1). @property name; 声明的属性会自动生成_name实例变量和get/set方法的声明和实现部分。但是如果声明了@property name; 由同时重写了_name的get和set方法,则@property不帮忙生成_name了。如果只重写get/set其中的一个方法,@property仍然帮忙生成_name;
(2). 如果声明了@property(readonly)name; 编译器会自动帮忙生成_name和get方法。但此时如果重写get方法,@property不帮忙生成_name;
17.
利用MJExtension替换模型中的服务器返回的不合适的property(如id,description等)的方法
#import <MJExtension.h>
@implementation WZTopic {
//替换模型中的原有key(给NSObject增加的非正式协议)
+ (NSDictionary *)mj_replacedKeyFromPropertyName {
return @{ @"ID":@"id" };
}
//可以批量替换所有的property(给NSObject增加的非正式协议)
+ (NSString *)mj_replacedKeyFromPropertyName121:(NSString *)propertyName {
if ([propertyName isEqualToString: @"id"]) return @"ID";
return propertyName;// 其他情况直接返回
}
18. 在不知道图片扩展名的情况下,如何知道图片的真实类型?
(1) 根据图片扩展名判断(不一定准确)。BOOL isGif = [imagePath.pathExtension.lowercaseString isEqualToString:@"gif"];
(2) 最准确的做法:取出图片二进制数据的第一个字节,进行判断。(图片的类型存储在二进制数据的第一个字节中)。 图片类型判断可参考SDWebImage中的"NSData+ImageContentType.h"分类
#import "NSData+ImageContentType.h" @implementation NSData (ImageContentType) + (NSString *)sd_contentTypeForImageData:(NSData *)data {
uint8_t c;
[data getBytes:&c length:];
switch (c) {
case 0xFF:
return @"image/jpeg";
case 0x89:
return @"image/png";
case 0x47:
return @"image/gif";
case 0x49:
case 0x4D:
return @"image/tiff";
case 0x52:
// R as RIFF for WEBP
if ([data length] < ) {
return nil;
}
NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(, )] encoding:NSASCIIStringEncoding];
if ([testString hasPrefix:@"RIFF"] && [testString hasSuffix:@"WEBP"]) {
return @"image/webp";
}
return nil;
}
return nil;
}
@end @implementation NSData (ImageContentTypeDeprecated)
+ (NSString *)contentTypeForImageData:(NSData *)data {
return [self sd_contentTypeForImageData:data];
}
@end
19.
iOS中通过核心动画和UIView都可以做动画,但是二者有什么区别呢?
20.
//1.字符串创建
NSString *str = [NSString stringWith...];
NSString *str = [[NSString alloc] initWith...];
//2.字符串常用的处理方法
NSString *str = @"5445546564";
NSString *newStr = [str stringBy....];
//3.String和subString
NSString *str = @"5445546564";
NSString *newStr = [str substring...];
//4.字符串替换
NSString *str = @"h-e-l-l-o, w-o-r-l-d";
NSString *newStr = [str stringByReplacingOccurrencesOfString:@"-" withString:@""];
NSLog(@"str:%@,newStr:%@",str,newStr);
打印结果:str:h-e-l-l-o, w-o-r-l-d,newStr:hello, world
21.
利用UIGestureRecognizer,能轻松识别用户在某个view上面做的一些常见手势。UIGestureRecognizer是一个抽象的基类,定义了所有手势的基本行为,不能直接使用。需使用UIGestureRecognizer的子类才能处理具体的手势,具体如下:
UITapGestureRecognizer //(敲击) //较常用
UIPinchGestureRecognizer //(捏合,用于缩放)
UIPanGestureRecognizer //(拖拽)
UISwipeGestureRecognizer //(轻扫)
UIRotationGestureRecognizer //(旋转)
UILongPressGestureRecognizer //(长按)
注意:UIView,UIImgeView默认是不接收手势事件的,在添加手势前,需设置view.userInteraction = YES; UIButton该属性默认是YES,不要设置。
22.
在自定义的UIView中,如果想push/present modally视图控制器,因为self是UIView类不能弹出控制器(只有ViewController才能弹出控制器),通常做法是通过UIApplication单例获取根视图控制器,用它在自定义View中弹出视图控制器。
//通过单例拿到根控制器来显示vc
[[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:vc animated:YES completion:nil];
23. 自定义view的xib不要和控制器重名
24.
注意:以后凡是看到系统自带的类xxxItem,肯定是苹果封装好的Model模型,它并不是UI控件,而是继承自NSObject的模型。 例如:navigationItem是用来给navigationBar提供显示数据的模型,UIBarButtonItem是用来给UINavigationItem提供数据的模型,他们是继承自NSObject的模型,并不是UI控件。(猜想:苹果在UIViewController.h中增加navigationItem模型属性,在vc.navigationItem.title方法的内部实现,肯定是调用了vc.navigationController.navigationBar.titleLabel.text来设置的)。
[BS] 小知识点总结-04的更多相关文章
- [BS] 小知识点总结-05
[BS] 小知识点总结-05 1. 不论UIWindow的rootViewController是navC.tabBarC还是VC,也不管modalVC和rootVC中间隔着多少个VC,但是modal出 ...
- [BS] 小知识点总结-03
1.Autolayout中“constrain to margins” Autolayout中的页面边距的问题ios8以后的UIView增加了layoutMargins属性,在Storyboard/I ...
- [BS] 小知识点总结-02
1. dispatch_GCD 可让某操作延迟x秒执行 //模拟网速慢,延迟3s返回数据(就会导致右侧数据和左侧标签不对应) dispatch_after(dispatch_time(DISPATC ...
- [BS] 小知识点总结-01
1. UIImageView *imgView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"MainTitle&quo ...
- android 小知识点
小知识点总结 1. android中MotionEvent.ACTION_CANCEL事件如何被触发? 对于这个问题,android文档的说明很简短,想看明白很难.国外一网页说的还比较详细,写在这里分 ...
- 刚接触Linux,菜鸟必备的小知识点(一)
身为一个将要大四的学生,而且还是学计算机的没有接触过linux简直是羞愧难当.这个假期做了一个软件测试员,必须要熟悉linux的操作,所以对于我这个菜鸟我也就说几点比较重要的小知识点吧. 第一.cd指 ...
- Java学习过程中的总结的小知识点(长期更新)
Java学习过程中的总结的小知识点 (主要是自己不会的知识和容易搞错的东西) 计算某个程序运行的时间 long stime=System.currentTimeMillis(); copy3(file ...
- 【转】HTML5的小知识点小集合
html5的小知识点小集合 html5知识 1. Doctype作用?标准模式与兼容模式各有什么区别? (1).<!DOCTYPE>声明位于位于HTML文档中的第一行,处于<h ...
- AngularJS的小知识点
小知识点:$scope和$rootScope (1)每次使用ngController指令,都会调用控制器的创建函数,创建出一个控制器对象. (2)每次创建一个控制器对象,AngularJS都会创建一个 ...
随机推荐
- 使用Eclipse自带Web Service插件(Axis1.4)生成Web Service服务端/客户端
创建一个名字为math的Java web工程,并将WSDL文件拷入该工程中 将Axis所需的jar包拷贝至WebRoot\WEB-INF\lib目录下,这些jar包会自动导入math工程中 一,生成W ...
- centos 使用pip安装mysql-python
直接使用# pip install mysql-python 命令报 EnvironmentError: mysql_config not found 错误 安装mysql-phthon 需要用的my ...
- PHP 常用函数库和一些实用小技巧
PHP 常用函数库和一些实用小技巧 作者: 字体:[增加 减小] 类型:转载 包括文件读取函式,文件写入函式,静态页面生成函式,目录删除函式等 文件读取函式 //文件读取函式 function ...
- nginx服务器安装与启动
nginx服务器介绍 1.nginx服务器功能 nginx服务器可以扮演:轻量级的web服务器.应用服务器.代理服务器.反向代理服务器.后台服务器.CDN缓存服务器 nginx的基本模块: 内核模块C ...
- mysql中文字段转拼音首字母,以及中文拼音模糊查询
创建存储过程,将中文字段转拼音首字母 CREATE DEFINER=`root`@`%` FUNCTION `fristPinyin`(P_NAME VARCHAR(255)) RETURNS var ...
- vm设置静态ip
1. 进入虚拟linux系统中,vim /etc/sysconfig/network-scripts/ifcfg-eth0,里面保留以下内容即可: DEVICE=eth0 //使用的网卡标识 BOOT ...
- oracle communities
应该常来这看看 https://www.oracle.com/communities/index.html
- PHP 加密 和 解密 方法
关于Discuz的加密解密函数,相信大家都有所了解,该authcode函数可以说是对PHP界作出了重大的贡献,真的发觉discuz这个函数写的太精彩啦. 研究了一下这个算法,总的来说可以归纳为以下三点 ...
- SecureCRT登录Ubuntu 的中文乱码问题
(1)/var/lib/locales/supported.d/local文件中添加一行:zh_CN.UTF-8 UTF-8,执行sudo locale-gen下载文件 su - root (2) ...
- 更新Delphi中SVN客户端版本的方法
Delphi从XE以后集成里SVN客户端, 安装完Delphi以后, 在bin\subversion下, 存放的就是SVN客户端文件, 可惜版本有点低(好像是1.7的) 如果想更新成高版本的客户端文件 ...