1,NSThread
1.1 创建线程的方法
#pragma mark - 创建线程的方法
//创建线程的方法 3
- (void)test3
{
//隐式的创建线程,通过这种方法实际上也会创建新的线程
[self performSelectorInBackground:@selector(run) withObject:nil];
}
//创建线程的方法 2
- (void)test2
{
//通过类方法创建一个新线程
[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];
}
//创建线程的方法 1
- (void)test1
{
//1,实例化一个线程对象
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
//2,让线程开始工作,
[thread start];
}
- (void)run
{
// 1,睡到指定的时间点
// [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:5.0]];
for (int i = 0; i < 10; i++) {
//2,[NSThread sleepForTimeInterval:0.3f] 这个类方法,让当前进程睡一会
[NSThread sleepForTimeInterval:0.3f];
//3,[NSThread currentThread] 通过这个类方法,打印出当前的进程
NSLog(@"%@ %d", [NSThread currentThread], i);
//4,[NSThread mainThread] 获取主线程
NSThread *main = [NSThread mainThread];
}
//5.在指定线程上执行操作
[self performSelector:@selector(run1) onThread:[NSThread mainThread] withObject:nil waitUntilDone:YES];
//6.在主线程上执行操作
[self performSelectorOnMainThread:@selector(run1) withObject:nil waitUntilDone:YES];
//7.在当前线程执行操作
[self performSelector:@selector(run1) withObject:nil];
}
1.2 线程的属性
#pragma mark - 线程的属性
- (void)test4
{
/*
1,thread.name = @"my thread"; //设置线程的名字,打印出来,方便程序出错的时候查找是哪里出错了
2,thread.threadPriority = 0.5; //线程的优先级,是一个浮点数,0.0 ~ 1.0.默认值是0.5,开发时候一般不要去修改优先级,否则可能会导致程序出错,另外,需要被调用很多很多次,才能体现出来优先级的作用。
*/
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
thread.name = @"my thread";
thread.threadPriority = 0.5;
//3. 放到可调度线程池,等待被调度。 这时候是就绪状态
[thread start];
//4, 一旦强制终止,就在不能重新启动
// 一旦强制终止,后面的代码都不会执行
[NSThread exit];
}
1.3 为什么只能在主线程中更新UI
/*
线程安全的概念: 就是在多个线程同时执行的时候,能够保证资源信息的准确性.
"UI线程" -- 主线程
** UIKit 中绝对部分的类,都不是”线程安全“的
怎么解决这个线程不安全的问题?
苹果约定,所有程序的更新UI都在主线程进行, 也就不会出现多个线程同时改变一个资源。
// 在主线程更新UI,有什么好处?
1. 只在主线程更新UI,就不会出现多个线程同时改变 同一个UI控件
2. 主线程的优先级最高。也就意味UI的更新优先级高。 会让用户感觉很流畅
*/
1.4 互斥锁 Demo
#pragma mark - 卖票
/**
1. 开发比较复杂的多线程程序时,可以先在主线程把功能实现
2. 实现功能以后,再把耗时的功能再放到子线程
3. 再增加一个线程,建议开发的时候,线程一个一个增加
*/
/**
加锁,互斥锁
加锁,锁定的代码尽量少。
加锁范围内的代码, 同一时间只允许一个线程执行
互斥锁的参数:任何继承 NSObject *对象都可以。
要保证这个锁,所有的线程都能访问到, 而且是所有线程访问的是同一个锁对象
*/
- (void)saleTicktes
{
while (YES) {
// 模拟一下延时,卖一张休息1秒
[NSThread sleepForTimeInterval:1.0];
// 不会写单词,怎么办?
// [[NSUserDefaults standardUserDefaults] synchronize];
// 为什么没有提示
// 因为苹果不推荐我们使用加锁。因为加锁,性能太差。
@synchronized(self){ // 开发的时候,一般就使用self就OK
//1. 判断是否还有票,
if (self.tickets > 0) {
// 2. 如果有票,就卖一张
self.tickets--;
NSLog(@"剩余的票数--%d--%@", self.tickets, [NSThread currentThread]);
}else{
// 3. 如果没有就返回
NSLog(@"没票了");
break;
}
}
}
}
1.5 原子属性和非原子属性(nonatomic,atomic)
@property(nonatomic, assign) int tickets;
@property(atomic, strong)NSObject *obj;
// nonatomic 非原子属性
// atomic 原子属性--默认属性
// 原子属性就是针对多线程设计的。 原子属性实现 单(线程)写 多(线程)读
// 因为写的安全级别要求更高。 读的要求低一些,可以多读几次来保证数据的正确性
// 如果同时重写了setter和getter方法,"_成员变量" 就不会提供
// 可以使用 @synthesize 合成指令,告诉编译器属性的成员变量的名称
@synthesize obj = _obj;
- (NSObject *)obj
{
return _obj;
}
// atomic情况下, 只要重写了set方法,getter也得重写
- (void)setObj:(NSObject *)obj
{
// 原子属性内部使用的 自旋锁
// 自旋锁和互斥锁
// 共同点: 都可以锁定一段代码。 同一时间, 只有线程能够执行这段锁定的代码
// 区别:互斥锁,在锁定的时候,其他线程会睡眠,等待条件满足,再唤醒
// 自旋锁,在锁定的时候, 其他的线程会做死循环,一直等待这条件满足,一旦条件满足,立马去执行,少了一个唤醒过程
@synchronized(self){ // 模拟锁。 真实情况下,使用的不是互斥锁。 而是自旋锁
_obj = obj;
}
}
2,OC中的链式编程
实现过程见Demo。思路,要实现链式编程可以让函数返回值是对象本身即可,使用函数返回值就可以直接使用'.'操作符来调用其他函数,但是!这样写,调用的方法不能有参数,因为OC中有参数的方法必须使用中括号来调用, 为了实现传递参数,我们可以使用block代码块,让函数的返回值是一个block代码块,对象.[方法名],得到的结果是一个block代码块,然后我们再取执行block,执行block代码块的方法就是对象.[方法名](), 括号中是block代码块的参数,这样我们就实现了链式编程,,详见代码。
Demo
</pre><pre name="code" class="objc">typedef WHAttributeText *(^WHBlockFloat)(CGFloat);
typedef WHAttributeText *(^WHBlockColor)(UIColor *);
typedef WHAttributeText *(^WHBlockNumber)(NSNumber *);<p><pre name="code" class="objc">- (WHBlockFloat)paraLineSpacing;
- (WHBlockFloat)paraSpacing;
- (WHAttributeText *(^)(NSTextAlignment))paraAlignment;
- (WHBlockFloat)paraFirstLineHeadIndent;
- (WHBlockFloat)paraMinimumLineHeight;
- (WHBlockFloat)paraLineSpacing
{
return ^(CGFloat lineSpacing){
_whParagrahStyle.lineSpacing = lineSpacing;
return self;
};
}
- (WHBlockFloat)paraSpacing
{
return ^(CGFloat paragraphSpacing){
_whParagrahStyle.paragraphSpacing = paragraphSpacing;
return self;
};
}
- (WHAttributeText *(^)(NSTextAlignment))paraAlignment
{
return ^(NSTextAlignment alignment){
_whParagrahStyle.alignment = alignment;
return self;
};
}
使用:
对象. paraHeadIndent(8).paraLineSpacing(10);
3,IOS开发中的结构体
3.1 结构体和字符串之间的相互转换
如下所示,其它结构体也有类似的函数
结构体和字符串之间相互转换:
NSString *NSStringFromCGPoint(CGPoint point);
NSString *NSStringFromCGRect(CGRect rect);
CGPoint CGPointFromString(NSString *string);
CGRect CGRectFromString(NSString *string);
3.2,CGRect放大或缩小,中心为原点
//对一个CGRect进行修改 以这个的中心来修改 正数表示更小(缩小) 负数表示更大(放大)
CGRect CGRectInset(CGRect rect, CGFloat dx, CGFloat dy);
3.3 比较两个矩形是否相交
bool CGRectIntersectsRect(CGRect rect1, CGRect rect2);
3.4 初始为0的 结构体
const CGPoint CGPointZero;
const CGRect CGRectZero;
const CGSize CGSizeZero;
3.5 偏移
CGRect类型的矩形,相对于x,y,的偏移
CGRect CGRectOffset(CGRect rect, CGFloat dx, CGFloat dy)
3.6 获取屏幕尺寸
CGrect screenBounds = [ [UIScreen mainScreen]bounds];//返回的是带有状态栏的Rect
CGRect viewBounds = [ [UIScreen mainScreen]applicationFrame];//不包含状态栏的Rect
//screenBounds 与 viewBounds 均是相对于设备屏幕来说的
//所以 screenBounds.origin.x== 0.0 ; screenBounds.oringin.y = 0.0; screenBounds.size.width == 320; screenBounds.size.height == 480(或者其他分辨率有所差异)
//所以 screenBounds.origin.x== 0.0 ; screenBounds.oringin.y = 20.0;(因为状态栏的高度是20像素) screenBounds.size.width == 320; screenBounds.size.height == 480