我的|我的 iOS 学习小记

啰嗦一句 之前使用的博客系统似乎要停掉了, 自己经常会记录一些易忘记的代码片段, 还是拷贝到来吧...不支持自动生成大纲目录啊...这好尴尬...
持续继承 Jenkins 中 SVN 由于服务器时间不一致导致无法更新到最新版本
在链接中增加@HEAD
https://xxxxx/项目名称@HEAD
xib技巧 xib中用 UIColor 设置边框颜色
选中xib中的label,在右边栏的第三个标签页中第三项是User Defined Runtime Attributes
添加一个keyPath,keyPath值为layer.borderWidth,类型为NSNumber,值为你想要设置的边框宽度。第二个是设置边框的颜色layer.borderColorFromUIColor,为了兼容CALayer 的KVC ,你得给CALayer增加一个分类

@implementation CALayer (Additions) - (void)setBorderColorFromUIColor:(UIColor *)color { self.borderColor = color.CGColor; } @end

在 xib 中添加 xib
在 subview 的 xib 中添加如下代码和属性
@property (nonatomic, strong) IBOutlet UIView *view;

- (instancetype)initWithCoder:(NSCoder *)aDecoder { if (self = [super initWithCoder:aDecoder]) { [self setup]; } return self; }- (void)setup {[[NSBundle mainBundle] loadNibNamed:@"ANScanDrawView" owner:self options:nil]; [self addSubview:self.view]; [self.view mas_makeConstraints:^(MASConstraintMaker *make) { make.top.left.bottom.right.equalTo(self); }]; }

修改 subview 的 xib 的 file's Owner 为其 Class 并且拖拽 view 属性.
就可以在 superview 的 xib 中就可以和正常操作一样添加 subview 了.记得指定 Custom Class.
约束 别挤我
Content Compression Resistance = 不许挤我!
这个属性的优先级(Priority)越高,越不“容易”被压缩。也就是说,当整体的空间装不下所有的View的时候,Content Compression Resistance优先级越高的,显示的内容越完整。
Content Hugging = 抱紧!
这个属性的优先级越高,整个View就要越“抱紧”View里面的内容。也就是说,View的大小不会随着父级View的扩大而扩大。
topLayoutGuide和bottomLayoutGuide
就是直接使用UILayoutSupport定义的length属性。
这个时候就有个地方要特别注意,在运行到viewDidLoad的时候,length的值是0,因为这个时候界面还没有被绘制,所以一个解决方法就是在ViewController的updateViewConstraints方法里面去使用length值添加约束。如下:
- (void)updateViewConstraints { [_topView mas_updateConstraints:^(MASConstraintMaker *make) { // 直接利用其length属性 make.top.equalTo(self.view.mas_top).with.offset(self.topLayoutGuide.length); }]; [super updateViewConstraints]; }

在Masonry的新版中,为UIViewController增加了一个新的Category: MASAdditions,增加了mas_topLayoutGuide和mas_bottomLayoutGuide两个方法。
自定义baseline
【我的|我的 iOS 学习小记】对于自定义的View来说,baseline默认就是整个view的底部,如果想改变baseline的话,可以重写UIView的viewForBaselineLayout,返回当成baseline的view即可。
- (UIView *)viewForBaselineLayout { return _imageView; }

导航栏 TitleView Frame 异常的问题
  • 在自定义titleview 里重写 intrinsicContentSize 属性,代码如下
@property (nonatomic, assign) CGSize intrinsicContentSize;

  • 在赋值到 TitleView 之前指定属性的 Size 即可.
UITableView UITableViewStyleGrouped的几个问题
  • Plain的时候Section的Header和Footer会默认悬停,Grouped不会.
  • 如果用Grouped的话,第一个Section Header会莫名其妙不见,必须使用代理方法返回Section Header的高度,而不能给TableView直接赋值.tableView.sectionHeaderHeight=86;
  • 给TableView的tableFooterView和tableHeaderView指定一个0.01高度的UIView可以消除Grouped多余的头部和底部的间隙, 直接指定0是不行的.
UINavigationController push 的时候界面卡死的问题
@interface ANNavigationController () @end@implementation ANNavigationController- (void)viewDidLoad { [super viewDidLoad]; //代理 self.delegate = self; }/** 由控制器控制状态栏颜色 */ - (UIViewController *)childViewControllerForStatusBarStyle{ return self.topViewController; }- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {if (self.viewControllers.count > 0) {viewController.hidesBottomBarWhenPushed = YES; /** 加入全局右滑 POP 功能 */ self.interactivePopGestureRecognizer.delegate = nil; } [super pushViewController:viewController animated:animated]; }- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated { if (viewController == navigationController.viewControllers[0]) { navigationController.interactivePopGestureRecognizer.enabled = NO; } else { navigationController.interactivePopGestureRecognizer.enabled = YES; } }@end

NSString 过滤非法字符
通过巧妙的拆分再合并去除特殊字符
NSCharacterSet *set = [NSCharacterSet characterSetWithCharactersInString:@"\"/\\ <>*|'"]; NSString *trimmed = [[string componentsSeparatedByCharactersInSet:set] componentsJoinedByString: @""];

Data 的字符串转 NSData
- (NSData *)dataWithHexString:(NSString *)hexString { NSInteger len = [hexString length]; char *myBuffer = (char *)malloc(len / 2 + 1); bzero(myBuffer, len / 2 + 1); for (int i = 0; i < len - 1; i += 2) { unsigned int anInt; NSString * hexCharStr = [hexString substringWithRange:NSMakeRange(i, 2)]; NSScanner * scanner = [NSScanner scannerWithString:hexCharStr] ; [scanner scanHexInt:&anInt]; myBuffer[i / 2] = (char)anInt; } NSData *hexData = https://www.it610.com/article/[[NSData alloc] initWithBytes:myBuffer length:len/2]; free(myBuffer); return hexData; }

截取字符串时 emoji 乱码的问题
因为 emoji 的 length 并不是1, 所以按长度截取 emoji 会出现乱码问题
if (sender.text.length > kMaxLength) { NSRange range = [sender.text rangeOfComposedCharacterSequenceAtIndex:kMaxLength]; sender.text = [sender.text substringToIndex:range.location]; }

WKWebView 预览资源, 如 PDF Excel Word 等.显示过小, 需要放大怎么办.
NSString *jScript = @"var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta); "; WKUserScript *wkUScript = [[WKUserScript alloc] initWithSource:jScript injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES]; WKUserContentController *wkUController = [[WKUserContentController alloc] init]; [wkUController addUserScript:wkUScript]; WKWebViewConfiguration *wkWebConfig = [[WKWebViewConfiguration alloc] init]; wkWebConfig.userContentController = wkUController; WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:wkWebConfig];

成长 记录着自己怎样进入了 iOS 的世界...
2016-06 学习日记
2016-06-03
  1. LaunchImage : Launch Images Source -> LaunchImage
  2. AppIcon : iOS icon is pre-rendered 不需要系统渲染
  3. 创建窗口和根视图控制器
  4. 添加子控制器UITableViewController
  5. 自定义TabBarController
2016-06-06
  1. 项目分层
  2. PCH import
  3. 创建UITableViewController子类
  4. 创建UINavigationController并设置子控制器
  5. 创建UINavigationController的子类,设置hidesBottomBarWhenPushed
2016-06-07
  1. UINavigationController的UIBarButtonItem的Extension自定义
  2. 拦截push操作实现统一的导航栏按钮
  3. 设置整个项目UIBarButtonItem的主题颜色
  4. 根据是否是DEBUG来控制是否打印日志.
    • (void)initialize 只在第一次使用的时候调用一次
2016-06-13
  1. 设置UINavigationBar的主题 背景图片
  2. [NSMutableDictionary dictionaryWithDictionary:xxx] 字典拷贝
  3. 创建UISearchBar
  4. 用UITextField来 订制 UISearchBar
  5. 用继承来实现自定义控件
  6. 继承UIButton实现文字在左图标在右的按钮
2016-06-14
  1. iOS 10 真棒!
  2. 自定义控件,弹出菜单,通过UIButton作为遮罩,加上UIImageView显示图片完成.
  3. 代理 Delegate
  4. 扩展UIView, 增加x y centerX centerY width height size属性,操作简便
  5. 扩展弹出菜单,以增加功能
  6. 枚举
  7. 研究UITabBar控件,学会举一反三,研究复杂控件结构,学会对私有类型进行处理
2016-06-15
  1. 自定义TabBar 遍历SubViews来修改布局以及增加按钮
  2. KVC和OC运行时机制来使UITabBarViewController的TabBar替换为我们自定义的TabBar
2016-06-16
  1. work..打包...
  2. 复习代理,监听TabBar中加号按钮的点击事件
  3. 自定义控制器和NavigationViewController initWithRootViewController来进行present和dismiss
2016-06-20
  1. work..打包...
  2. 图片拉伸的问题
  3. 第一次运行当前版本的判断 NSUserDefaults [[NSBundle mainBundle].infoDictionary
  4. CFStringRef和NSString之间的相互桥接转换 __bridge
  5. 获取屏幕宽度
  6. UIScrollView + PageControl制作新特性页面
2016-06-21
  1. 完善新特性页面,添加按钮
  2. 按钮制作复选框效果.
  3. 切换根控制器 UIWindow *window = [UIApplication sharedApplication].keyWindow;
  4. OAuth
  5. UIWebView 发送请求以及 通过代理拦截请求
2016-06-22
  1. AFNetworking 发送GET/POST请求
  2. MBProgressHUD 显示loading提示
  3. MJExtension 模型和字典的转换
  4. 了解运行时
  5. plist和Object的归档和解档
2016-06-23
  1. AFNetworking 不支持的Response ContentType在AFURLResponseSerialization.m中找到对应的类修改init方法中加载的默认ContentType类型
  2. SDWebImage 异步图像下载 以及 内存警告时候的缓存清理
  3. UITableView 加载数据
  4. 大F到手,无心学习了....罪过...
2016-06-24
  1. AFNetworking 监听网络状态的切换
  2. 自带的UIRefreshControl实现下拉刷新(继承自UIControl,通过AddTarget实现操作)
...支撑能力开放平台项目... 2016-07 学习日记
2016-07-12
  1. 复习
  2. 延时执行代码
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // CODE; });

  1. UILabel的简单位移动画,来实现刷出新微博的消息提示
  2. 利用 Xib 自定义一个UIView,实现上拉刷新组件.
  3. 上拉刷新的实现关于高度计算没太明白...后续再看看...
  4. 自定义TextView,实现带提示文字的功能
  5. 通知,增加通知来监听TextView的文字变化 (dealloc要移除)
2016-07-26
  1. 自定义UIView实现工具条, 按钮的Tag赋值一个枚举类型,来区分不同的按钮
  2. TextView.alwaysBounceVertical = YES
  3. viewDidAppear中TextView成为第一响应者,以便自动弹出键盘
  4. 成为TextView代理scrollViewWillBeginDragging方法中,设置视图endEditing,关闭键盘
2016-07-27
  1. 代开系统照相机和相册 来提供一张照片.通过代理实现图片的获取,添加到自己定义的UIView中.
  2. 自定义UIView在TextView中显示图片.
  3. AFN发送微博, form-data编码格式传送图片
2016-07-28
  1. 重构,分层
  2. NSTimer 获取 未读消息
  3. TabBarItem 未读消息的显示 badgeValue
  4. 应用未读消息的显示
    [UIApplication sharedApplication].applicationIconBadgeNumber
  5. APP 进入后台后申请继续运行
2016-07-29
  1. 控制 TableView 滚动 (点击 TabBarItem 触发) scrollToRowAtIndexPath
2016-08 学习日记
2016-08-01
  1. 在 iOS 8 之后,设置应用的未读消息需要申请通知权限
float version = [[[UIDevice currentDevice] systemVersion] floatValue]; if (version >= 8.0) { UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge categories:nil]; [[UIApplication sharedApplication] registerUserNotificationSettings:settings]; [application registerForRemoteNotifications]; }

  1. 自定义Cell和Frame, 注意分层减少依赖,以便后期维护.
2016-08-04
  1. 完善 Cell, TableView 的细节
  2. UILabel 多行,设置 numberOfLines = 0, 计算高度的时候用
CGSize textMaxSize = CGSizeMake(textMaxWidth, MAXFLOAT); [text boundingRectWithSize:textMaxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : YXStatusOrginalTextFont} context:nil].size

  1. 对于属性的转换和处理等, 思考一下 get方法 和 set方法 的合理运用.
2016-08-XX 出差这段时间了解了项目如何开发,了解了 Masonry 的使用. 虽然是在原有的项目上继续开发新需求, 但是还是感觉提升好大...
  1. 我自己斗胆引入 MJExtension , 开发效率提升很大
  2. 了解了 Masonry 的使用
  3. 了解了一个项目的各 VC (Tabbar, Navi ...)之间的层次关系
  4. 最重要的一点是多个模块使用了 TableView, 更深入一点点的了解了 TableView 和自定义 Cell 的使用
  5. 在一些特定的需求中, 我还想到使用了 delegate 来解决, 熟悉了 protocol 的使用
  6. 最后还用了一段时间做了优化, 有些 VC 在 pop 之后并没有调用 dealloc 方法, 了解了 block 中的循环引用以及解决方法
    可以使用宏:
#define XYWeakSelf(type)__weak typeof(type) weak##type = type; #define XYStrongSelf(type)__strong typeof(type) type = weak##type;

NavigationController 的右滑 POP 功能
self.navigationController.interactivePopGestureRecognizer.delegate = (id) self;

2016-09 学习日记
2016-09-05 new 和 alloc init 的区别
[className new]基本等同于[[className alloc] init], 区别只在于alloc分配内存的时候使用了zone.它是给对象分配内存的时候,把关联的对象分配到一个相邻的内存区域内,以便于调用时消耗很少的代价,提升了程序处理速度.
利用dispatch_once创建单例
void dispatch_once( dispatch_once_t *predicate, dispatch_block_t block); 其中第一个参数predicate,该参数是检查后面第二个参数所代表的代码块是否被调用的谓词,第二个参数则是在整个应用程序中只会被调用一次的代码块。dispach_once函数中的代码块只会被执行一次,而且还是线程安全的。
+ (XYViewController *)sharedInstance { static XYViewController *vc; static dispatch_once_t one; dispatch_once(&one, ^{ vc = [[self alloc] init]; }); return vc; }

2016-09-06 继续看微薄的Demo, 保留一位小数 %.1f 发现 NSString 转换 NSDate 的时候返回 nil , 不知道为什么之前好使, 现在不好使了, 增加了一下 locole 属性的设置就好了
// Tue Sep 06 15:03:00 +0800 2016 NSDateFormatter *dfm = [[NSDateFormatter alloc] init]; dfm.dateFormat = @"EEE MMM dd HH:mm:ss Z yyyy"; // 增加这一行 dfm.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]; NSDate *createDate = [dfm dateFromString:_created_at];

CGRect 的 坐标系转换
[view convertRect:(CGRect) toView:(nullable UIView *)]; [view convertRect:(CGRect) fromView:(nullable UIView *)];

2016-09-22 AVFoundation 实现扫描二维码
[文章](http://www.jianshu.com/p/6b7d54b3f88b)

如果用户不允许访问相机. 应用会闪退, 加入判断
NSString *mediaType = AVMediaTypeVideo; //读取媒体类型 AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:mediaType]; //读取设备授权状态 if(authStatus == AVAuthorizationStatusRestricted || authStatus == AVAuthorizationStatusDenied){ //不允许 }

2016-09-27 提供单例时, 建议私有init方法, 利用如下声明(.h), 提供一个编译错误:
- (instancetype)init __attribute__((unavailable("Disabled. Use +sharedInstance instead")));

注意: 此时在sharedInstance方法中,需要写[[self alloc] init]
2016-09-28 打印一堆莫名其妙看不懂的Log Edit Scheme-> Run -> Arguments, 在Environment Variables里边添加
OS_ACTIVITY_MODE = Disable
2016-10 学习日记
2016-10-13 突发奇想用LaunchScreen做载入图 添加UIImageView.通过添加约束设置拉伸全屏显示, 似乎不用提供各种尺寸的LaunchImage.
添加 Storyboard ID. "LaunchScreen"
UIViewController *viewController = [[UIStoryboard storyboardWithName:@"LaunchScreen" bundle:nil] instantiateViewControllerWithIdentifier:@"LaunchScreen"]; UIView *launchView = viewController.view; [UIView animateWithDuration:1.8f delay:0.1f options:UIViewAnimationOptionBeginFromCurrentState animations:^{ launchView.alpha = 0.0f; launchView.layer.transform = CATransform3DScale(CATransform3DIdentity, 1.3f, 1.3f, 1.0f); } completion:^(BOOL finished) { [launchView removeFromSuperview]; }];

来为启动增加动画, 这里我设置了延迟 0.1s , 因为还添加了一个label的移动动画, 如果不延迟的话会明显感觉有个小卡顿.
2016-10-24 获取各种目录
// 获取沙盒主目录路径 NSString *homeDir = NSHomeDirectory(); // 获取Documents目录路径 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *docDir = [paths objectAtIndex:0]; // 获取Caches目录路径 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); NSString *cachesDir = [paths objectAtIndex:0]; // 获取tmp目录路径 NSString *tmpDir =NSTemporaryDirectory();

2016-10-26 不知道为什么 Xcode Build 报错
/Users/hanyuanxu/Library/Developer/Xcode/DerivedData/DiaryForXY-atkiwvdprytfniattjbdfgjreltv/Build/Products/Debug-iphonesimulator/DiaryForXY.app: resource fork, Finder information, or similar detritus not allowed Command /usr/bin/codesign failed with exit code 1

网上说, 各种证书问题, 删除创建等等都无果
最后清空DerivedData目录, 工程目录下执行
xattr -rc .

解决, 并不懂...
2016-10-27 UITableView 的 Style UITableViewStylePlain 和 UITableViewStyleGrouped.
UITableViewStyleGrouped 默认会在 TableView 的 HeaderView 下面增加一条线的间隙, 会在 TableView 的 FooterView 上面增加微宽的间隙.

  • Reveal 使用方法 点这里
2016-11 学习日记
2016-11-14 全透明导航栏
- (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault]; [self.navigationController.navigationBar setShadowImage:[UIImage new]]; }- (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; [self.navigationController.navigationBar setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault]; [self.navigationController.navigationBar setShadowImage:nil]; }

还原的这部分放在 viewWillDisappear 好使,但是放在 viewDidDisappear 就不好使
我猜测是因为放在 viewDidDisappear 的时候当页面没了才会执行.这时候上一个页面已经渲染完了.所以就改不了了.
修改导航栏文字颜色
[self.navigationController.navigationBar setTitleTextAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:18],NSForegroundColorAttributeName:[UIColor blueColor]];

缩放动画
view.transform = CGAffineTransformMakeScale(0.01f, 0.01f); //将要显示的view按照正常比例显示出来 [UIView beginAnimations:nil context:UIGraphicsGetCurrentContext()]; [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; [UIView setAnimationDuration:0.8f]; //动画时间 view.transform=CGAffineTransformMakeScale(1.0f, 1.0f); //先让要显示的view最小直至消失 [UIView commitAnimations]; //启动动画

2016-12 学习日记
2016-12-02 原生提供的MD5加密方法 #import
+ (NSString *) md5:(NSString *)str {const char *cStr = [str UTF8String]; unsigned char result[CC_MD5_DIGEST_LENGTH]; CC_MD5(cStr, (CC_LONG)strlen(cStr), result); NSMutableString *ret = [NSMutableString stringWithCapacity:32]; for(int i = 0; i

2016-12-05 GCD 实现线程组,子线程全部结束后做出响应.
//创建线程租 dispatch_group_t group = dispatch_group_create(); //子线程1 dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{ ... }); //子线程2 dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{ ... }); dispatch_group_notify(group, dispatch_get_global_queue(0,0), ^{ //子线程全部执行完成后执行 ... });

如果线程里面有 block , 想在block结束后执行怎么办?
可以手动控制线程结束 :
//创建线程租 dispatch_group_t networking = dispatch_group_create(); //子线程1 dispatch_group_enter(networking); [A loadData:^(M*model) { ... dispatch_group_leave(networking); }]; //子线程2 dispatch_group_enter(networking); [B loadData:^(M*model) { ... dispatch_group_leave(networking); }]; dispatch_group_notify(networking,dispatch_get_main_queue(),^{ // 子线程全部执行完成后执行 ... });

2016-12-06 防止CollectionView更新的时候闪屏 CollectionView 更新的时候没找到带 Animation 参数的 暂时找到如下解决办法
[UIView performWithoutAnimation:^{ [self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]]; }];

2016-12-17 CocoaPods 相关问题 git clone之后pod install之后打开xcode报错
大致内容就是没有执行 pod install.可是我明明执行了..
百度之后说删除 Pods 目录 和 现有的 xcworkspace 重新 pod install即可
结果重新pod install的时候
Generating Pods project [1]63036 abortpod install

报了个错误一直没办法生成 xcworkspace 文件, 百度也无果.准备重新升级cocoapods
sudo gem install cocoa pods

结果又报了个错误
Operation not permitted - /usr/bin/xcodeproj

百度后执行命令
sudo gem install -n /usr/local/bin cocoapods

升级成功,通过
pod COMMAND --version

看到版本号是1.1.1, 执行 pod setup 成功后重新 pod install
结果依然报错..
Generating Pods project [1]63036 abortpod install

尝试升级beta版本
sudo gem install -n /usr/local/bin cocoapods --pre

看到版本号是1.2.0beta1, 执行 pod setup 成功后重新 pod install
Generating Pods project Integrating client project Sending stats Pod installation complete!

终于成功!猜测是创建工程的人使用了更高版本的CocoaPods.导致我没办法兼容.

    推荐阅读