开篇

第二星期开始,先和浩哥去看了美人鱼,就开始每天继续Coding-iOS的学习了。个人感觉这个Coding-iOS项目代码写的真好,开源之后简直就是iOS菜鸡开发者的福音。自己写起来之后,才发现coding速度真的是慢=。=

问题列表

  1. UITextField有关
  2. 自定义UITableViewCell流程
  3. NSUserDefaults基础
  4. dispatch_oncestatic 变量
  5. 创建category
  6. SHA1加密
  7. 2种enum类型
  8. Coding调用API流程
  9. MBProgressHUD基础
  10. keyWindow
  11. 文件操作有关
  12. 账户输入提示框
  13. enumerateObjectsUsingBlock:
  14. 2种UITableViewCell重用方式
  15. NSRange基础
  16. CAShapeLayer基础
  17. 显示/隐藏导航栏
  18. ViewController之间切换卡顿
  19. SDWebImageOptions
  20. category中新增property
  21. 用户名存储整个流程
  22. UIAlertController基础

UITextField有关

介绍几个UITextField的属性和方法

  1. secureTextEntry: 输入的文本不可见,多用于密码输入
  2. clearButtonMode: 清空文本输入的按钮的模式控制,属于UITextFieldViewMode。经常用到的有:UITextFieldViewModeNever, UITextFieldViewModeWhileEditing
  3. 触发事件: 常用的有 开始编辑(UIControlEventEditingDidBegin), 文本变更(UIControlEventEditingChanged), 结束编辑(UIControlEventEditingDidEnd)
  4. keyboardType: 键盘类型,可选的有 UIKeyboardTypeEmailAddress,
    UIKeyboardTypeDefault

自定义UITableViewCell流程

参考这里

NSUserDefaults基础

NSUserDefaults适合存储轻量级的本地数据,非常适合用来存储登录界面的数据(用户名,密码等等)。用法也很简单👇

  1. 存储数据
    1
    2
    3
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];        // 获取 defaults
    [defaults setObject:loginData forKey:@"loginData"]; // 存放登录数据
    [defaults synchronize]; // 同步到磁盘,避免数据丢失
  2. 读取数据
    1
    2
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];        // 获取 defaults
    NSDictionary *loginData = [defaults objectForKey:@"loginData"]; // 获取登录数据

dispatch_oncestatic 变量

dispatch_once函数只会被执行一次,经常用来创建单例实例,先来看看dispatch_once函数

1
void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block);

第二个参数是只会被执行一次的代码块,第一个参数用来判断代码块是否被执行。该函数与static变量一同使用,看看具体代码👇

1
2
3
4
5
6
7
8
9
+ (instancetype)sharedManager {
static Coding_NetAPIManager *manager = nil;
static dispatch_once_t pred;
dispatch_once(&pred, ^{
manager = [[Coding_NetAPIManager alloc] init];
});

return manager;
}

上面的static变量属于类成员,如果没有在.h文件中声明该static变量,那么他就是私有的类成员。类成员不能通过实例对象或是实例方法(-)去访问,只能通过类实例或是类方法(+)访问。

创建category文件

这个很简单啦,xcode -> New File -> Objective-C File -> 填写所需信息 -> Finish
例如,创建一个UIButton+Common的category,应该👇
category

SHA1加密

加密方法如下👇

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- (NSString *)sha1Str {
const char *cstr = [self cStringUsingEncoding:NSUTF8StringEncoding];
NSData *data = [NSData dataWithBytes:cstr length:self.length];

uint8_t digest[CC_SHA1_DIGEST_LENGTH];

CC_SHA1(data.bytes, (CC_LONG)data.length, digest);

NSMutableString *output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];

for (int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++) {
[output appendFormat:@"%02x", digest[i]];
}

return output;
}

注意 该方法写在了NSString的category里面

2种enum类型

指定enum有两种方式:
1.

1
2
3
4
5
6
typedef enum {
Get = 0,
Post,
Put,
Delete
} NetworkMethod;
  1. 1
    2
    3
    4
    5
    6
    typedef NS_ENUM(NSInteger, IllegalContentType) {
    IllegalContentTypeTweet = 0,
    IllegalContentTypeTopic,
    IllegalContentTypeProject,
    IllegalContentTypeWebsite
    };

Coding调用API流程

参考这里

MBProgressHUD基础

MBProgressHUD是一个用来显示提示信息的第三方库,效果图如下👇
MBProgressHUD demo

事例代码:

1
2
3
4
5
6
7
8
9
10
11
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.mode = MBProgressHUDModeText;
hud.detailsLabelFont = [UIFont boldSystemFontOfSize:15];
hud.detailsLabelText = @"tip from vanney9.com";
hud.margin = 10;
hud.removeFromSuperViewOnHide = YES;
[hud hide:YES afterDelay:2.0f];
}

keyWindow

1
[UIApplication sharedApplication].keyWindow

APP主界面

文件操作有关

3个与文件操作相关的方法

  1. [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
    该方法返回该APP的Documents目录,在真机上显示的结果如下:
    1
    /var/mobile/Containers/Data/Application/7DB19AAA-B9E7-40D8-AAFA-C5BA2FA91CF0/Documents
    在模拟机上显示的结果如下:
    1
    /Users/vanney/Library/Developer/CoreSimulator/Devices/FF2B6585-B815-4762-AC40-268D51742C85/data/Containers/Data/Application/82FEAB7E-9245-4BA8-88ED-A559034BA5F0/Documents
  2. [NSMutableDictionary dictionaryWithContentsOfFile:@”file name”];
    该方法读取@"file name"这个文件中的内容(注意:该文件应该存放键值对,一般XML文件),并返回由该键值对组成的NSMutableDictionary
  3. [loginDataList writeToFile:@”file name” atomically:YES];
    该方法中的loginDataList是一个NSMutableDictionary,这个方法将键值对写入@"file name"这个文件中

账户输入提示框

效果如下图👇
easeinput demo
实现该效果的步骤如下:

  1. 创建提示的UITableView
    显示提示的白色框框实际上是一个UITableView,UITableView的内容根据当前已经输入的内容进行改变,若没有输入到@符号,就从之前输入过的账户中搜索;若已经输入了@符号,就显示不同的邮箱后缀。
  2. 将上一步创建的UITableView添加到输入账号,密码的UITableView中,并将提示框UITableView的位置定在账号的cell下面。
  3. 至于两个UITableView的交互:当账号的cell中的UITextField内容发生变化时,调用提示框UITableView的一个block,传入当前UITextField的文本,对提示的内容进行实时的变换。

enumerateObjectsUsingBlock:

enumerateObjectsUsingBlock:方法和for-in类似,具体代码如下👇

1
2
3
4
NSDictionary *dict = @{@"a": @"1", @"b": @"2"};
[dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
NSLog(@"key: %@, value: %@", key, obj);
}];

推荐使用for-in方法,快。

2种UITableViewCell重用方式

UITableViewCell有两种dequeueReuse方法:

  1. - (id)dequeueReusableCellWithIdentifier:(NSString *)identifier;
    该方法是不用事先注册Cell,但是它可能返回nil;所以当返回nil时,需要重新init。示例代码如下👇
    1
    2
    3
    4
    5
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }
  2. - (id)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath;
    该方法在iOS6中取代了第一种方法,它可以保证一定会返回UITableViewCell,但是在初始化UITableView时,需要进行UITableViewCell的注册,如下👇
    1
    [_tableView registerClass:[CustomCell class] forCellReuseIdentifier:@"Cell"];
    于是在重用UITableViewCell,不需要判断是否为nil,代码如下👇
    1
    CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];

NSRange基础

NSRange是一个结构体,其定义如下👇

1
2
3
4
typedef struct _NSRange {
NSUInteger location;
NSUInteger length;
} NSRange;

其中location表示起始位置,length表示长度。

CAShapeLayer基础

CAShapeLayer继承自CALayer,它表示一个形状,有一个path属性用来描述该形状,然后可以对这个形状进行描边,填充等操作。示例代码如下👇

1
2
3
4
5
6
7
8
9
10
11
12
CAShapeLayer *layer = [CAShapeLayer layer];
// 创建path, 给layer添加path, 释放path
CGMutablePathRef pathRef = CGPathCreateMutable();
CGRect bounds = CGRectInset(cell.bounds, 0, 0);
CGPathAddRect(pathRef, nil, bounds);
layer.path = pathRef;
CFRelease(pathRef);
// 对layer进行填充操作
layer.fillColor = [UIColor colorWithWhite:1.0 alpha:0.8].CGColor;
// 添加layer
UIView *bgView = [[UIView alloc] initWithFrame:bounds];
[bgView.layer addSublayer:layer];

显示/隐藏导航栏

使用下列方法实现导航栏的显示或者隐藏

1
2
3
4
5
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// 隐藏导航栏,若Hidden设为NO,则显示导航栏
[self.navigationController setNavigationBarHidden:YES animated:YES];
}

ViewController之间切换卡顿

可能的原因:没有设置ViewController的backgroundColor=。=

SDWebImageOptions

1
2
3
4
5
6
7
8
9
10
11
12
13
typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
SDWebImageRetryFailed = 1 << 0,//下载失败了会再次尝试下载
WebImageLowPriority = 1 << 1,//当UIScrollView等正在滚动时,延迟下载图片(放置scrollView滚动卡)
SDWebImageCacheMemoryOnly = 1 << 2,//只缓存到内存中
SDWebImageProgressiveDownload = 1 << 3,// 图片会边下边显示
SDWebImageRefreshCached = 1 << 4,//将硬盘缓存交给系统自带的NSURLCache去处理
SDWebImageContinueInBackground = 1 << 5,//后台下载
SDWebImageHandleCookies = 1 << 6,// 通过设置NSMutableURLRequest.HTTPShouldHandleCookies = YES来处理存储在NSHTTPCookieStore中的cookie
SDWebImageAllowInvalidSSLCertificates = 1 << 7,// 允许不受信任的SSL证书。主要用于测试目的。
SDWebImageHighPriority = 1 << 8,
SDWebImageDelayPlaceholder = 1 << 9,
SDWebImageTransformAnimatedImage = 1 << 10,
};

category中新增property

正常情况下,在category中是不能新增property的,要按如下步骤进行=。=

  1. 导入头文件
    1
    #import <objc/runtime.h>
  2. 新增@property
    1
    @property (nonatomic, strong) UIActivityIndicatorView *buttonIndicatorView;
  3. 自定义settergetter
    1
    2
    3
    4
    5
    6
    7
    8
    9
    static char EAButtonIndicatorViewKey;

    - (void)setButtonIndicatorView:(UIActivityIndicatorView *)buttonIndicatorView {
    objc_setAssociatedObject(self, &EAButtonIndicatorViewKey, buttonIndicatorView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }

    - (UIActivityIndicatorView *)buttonIndicatorView {
    return objc_getAssociatedObject(self, &EAButtonIndicatorViewKey);
    }

用户名存储整个流程

参考这里

UIAlertController基础

从iOS8开始,UIAlertController开始替代UIAlertAction,先来看看UIAlertController的效果图👇
UIAlertController demo
实现代码👇

1
2
3
4
5
6
7
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:@"欢迎注册 Coding,请尽快去邮箱查收邮件并激活账号。如若在收件箱中未看到激活邮件,请留意一下垃圾邮件箱(T_T)。" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *ok = [UIAlertAction actionWithTitle:@"知道了" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[alertController dismissViewControllerAnimated:YES completion:nil];
}];

[alertController addAction:ok];
[self presentViewController:alertController animated:YES completion:nil];

参考

P.S

以上都不是重点,重点是ollie要过立了=。=