***********单例**************************************
http://www.kuqin.com/shuoit/20140120/337708.html对单例创建安全有考虑。普通创建模式://头文件 提供类方法API#import@interface ZBSingleton : NSObject
+ (instancetype) shareInstance;
@end
//实现文件
#import "ZBSingleton.h"
@implementation ZBSingleton
//static 修饰全局,声明一个唯一内存的变量,初始化为nil
static ZBSingleton* _instance = nil;
//类方法返回唯一对象,而且痣被初始化一次
+(instancetype)shareInstance
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[super allocWithZone:NULL] init];
});
return _instance;
}
//重写alloc 方法:不会被alloc init重新分配新地址,返回当前实例对象
+(id)allocWithZone:(struct _NSZone *)zone
{
return [ZBSingleton shareInstance];
}
//重写copy方法,返回当前实例对象
-(id) copyWithZone:(struct _NSZone *)zone
{
return [ZBSingleton shareInstance];
}
******GCD - Operation等*************************
http://www.jianshu.com/p/0b0d9b1f1f19
1、GCD
(1)表格关系:
同步执行 异步执行
串行队列 当前线程,一个一个执行 其他线程,一个一个执行
并行队列 当前线程,一个一个执行 开很多线程,一起执行
(2)关于队列:
》》主队列:一个特殊的 串行队列。什么是主队列:用于刷新 UI,任何需要刷新 UI 的工作都要在主队列执行,
所以一般耗时的任务都要放到别的线程执行。
//OBJECTIVE-C
dispatch_queue_t queue = ispatch_get_main_queue();
//SWIFT
let queue = ispatch_get_main_queue()
》》自己创建的队列:自己可以创建 串行队列, 也可以创建 并行队列。
它有两个参数,第一个上面已经说了,第二个才是最重要的。
第二个参数用来表示创建的队列是串行的还是并行的,
传入 DISPATCH_QUEUE_SERIAL 或 NULL 表示创建串行队列。serial
传入 DISPATCH_QUEUE_CONCURRENT 表示创建并行队列。
concurrent
//OBJECTIVE-C
//串行队列
dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", NULL);
dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_SERIAL);
//并行队列
dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_CONCURRENT);
//SWIFT
//串行队列
let queue = dispatch_queue_create("tk.bourne.testQueue", nil);
let queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_SERIAL)
//并行队列
let queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_CONCURRENT)
》》全局并行队列:只要是并行任务一般都加入到这个队列。这是系统提供的一个并发队列。
//OBJECTIVE-C
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//SWIFT
let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
//1.任务一:下载图片
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"下载图片 - %@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:1.0];
}];
。。。
。。。
//4.设置依赖
[operation2 addDependency:operation1]; //任务二依赖任务一
[operation3 addDependency:operation2]; //任务三依赖任务二
注意:不能添加相互依赖,会死锁,比如 A依赖B,B依赖A。
可以使用 removeDependency 来解除依赖关系。
//5.创建队列并加入任务
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperations:@[operation3, operation2, operation1] waitUntilFinished:NO];
*******线程冲突问题******************
2.1、@synchronized ['s??kr? na?z d]同步
NSObject *obj = [[NSObject alloc] init];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@synchronized(obj) {
NSLog(@"需要线程同步的操作1 开始");
sleep(3);
NSLog(@"需要线程同步的操作1 结束");
}
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
sleep(1);
@synchronized(obj) {
NSLog(@"需要线程同步的操作2");
}
});
@synchronized(obj)指令使用的obj为该锁的唯一标识,只有当标识相同时,才为满足互斥,
如果线程2中的@synchronized(obj)改为@synchronized(self),刚线程2就不会被阻塞,
@synchronized指令实现锁的优点就是我们不需要在代码中显式的创建锁对象,便可以实现锁的机制,但作为一种预防措施,
@synchronized块会隐式的添加一个异常处理例程来保护代码,该处理例程会在异常抛出的时候自动的释放互斥锁。
所以如果不想让隐式的异常处理例程带来额外的开销,你可以考虑使用锁对象。
上面结果的执行结果为:
2016-06-29 20:48:35.747 SafeMultiThread[35945:580107] 需要线程同步的操作1 开始
2016-06-29 20:48:38.748 SafeMultiThread[35945:580107] 需要线程同步的操作1 结束
2016-06-29 20:48:38.749 SafeMultiThread[35945:580118] 需要线程同步的操作2
2.2、dispatch_semaphore
dispatch_semaphore_t signal = dispatch_semaphore_create(1);
dispatch_time_t overTime = dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_semaphore_wait(signal, overTime);
NSLog(@"需要线程同步的操作1 开始");
sleep(2);
NSLog(@"需要线程同步的操作1 结束");
dispatch_semaphore_signal(signal);
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
sleep(1);
dispatch_semaphore_wait(signal, overTime);
NSLog(@"需要线程同步的操作2");
dispatch_semaphore_signal(signal);
});
dispatch_semaphore是GCD用来同步的一种方式,与他相关的共有三个函数,
分别是dispatch_semaphore_create,dispatch_semaphore_signal,dispatch_semaphore_wait。
(1)dispatch_semaphore_create的声明为:
1
dispatch_semaphore_t dispatch_semaphore_create(long value);
传入的参数为long,输出一个dispatch_semaphore_t类型且值为value的信号量。
值得注意的是,这里的传入的参数value必须大于或等于0,否则dispatch_semaphore_create会返回NULL。
(2)dispatch_semaphore_signal的声明为:
long dispatch_semaphore_signal(dispatch_semaphore_t dsema);
这个函数会使传入的信号量dsema的值加1;
(3) dispatch_semaphore_wait的声明为:
long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);
这个函数会使传入的信号量dsema的值减1;这个函数的作用是这样的,如果dsema信号量的值大于0,该函数所处线程就继续执行下面的语句,
并且将信号量的值减1;如果desema的值为0,那么这个函数就阻塞当前线程等待timeout(注意timeout的类型为dispatch_time_t,
不能直接传入整形或float型数),如果等待的期间desema的值被dispatch_semaphore_signal函数加1了,
且该函数(即dispatch_semaphore_wait)所处线程获得了信号量,那么就继续向下执行并将信号量减1。
如果等待期间没有获取到信号量或者信号量的值一直为0,那么等到timeout时,其所处线程自动执行其后语句。
dispatch_semaphore 是信号量,但当信号总量设为 1 时也可以当作锁来。在没有等待情况出现时,它的性能比 pthread_mutex 还要高,
但一旦有等待情况出现时,性能就会下降许多。相对于 OSSpinLock 来说,它的优势在于等待时不会消耗 CPU 资源。
如上的代码,如果超时时间overTime设置成>2,可完成同步操作。如果overTime<2的话,在线程1还没有执行完成的情况下,
此时超时了,将自动执行下面的代码。
上面代码的执行结果为:
2016-06-29 20:47:52.324 SafeMultiThread[35945:579032] 需要线程同步的操作1 开始
2016-06-29 20:47:55.325 SafeMultiThread[35945:579032] 需要线程同步的操作1 结束
2016-06-29 20:47:55.326 SafeMultiThread[35945:579033] 需要线程同步的操作2
如果把超时时间设置为<2s的时候,执行的结果就是:
2016-06-30 18:53:24.049 SafeMultiThread[30834:434334] 需要线程同步的操作1 开始
2016-06-30 18:53:25.554 SafeMultiThread[30834:434332] 需要线程同步的操作2
2016-06-30 18:53:26.054 SafeMultiThread[30834:434334] 需要线程同步的操作1 结束
********************************************************************
@interfaceLTButton :UIButton
//-(void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents
-(void)addEvent:(UIControlEvents)event Block:(void(^)(UIButton*))block;
-(void(^)(UILabel*))returnBlock:(void(^)(UIButton*))block;
@end
***************************block*****************************************
#import"LTButton.h"
@interfaceLTButton()
@property(nonatomic,strong)void(^block)(UIButton*);
@property(nonatomic,strong)void(^labblock)(UILabel*);
@end
@implementationLTButton
//-(void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents{
//
//}
-(void)addEvent:(UIControlEvents)event Block:(void(^)(UIButton*))block{
self.block= block;
[selfaddTarget:selfaction:@selector(btnAction:)forControlEvents:event];
}
-(void)btnAction:(UIButton*)btn{
if(self.block) {
self.block(btn);
}
}
-(void(^)(UILabel*))returnBlock:(void(^)(UIButton*))block{
//self.block = block;
block(self);
//if (self.block) {
//self.block(self);
//
//}
//void (^blockstr)(NSString *) = ^(NSString *str1){
//str1 = @"str1";
//
//};
self.labblock= ^(UILabel*lab2){
lab2.text=@"ret lab name!";
};
returnself.labblock;
}
**************************block******************************************
@interfaceBlockVCtrl :UIViewController
@property(nonatomic,copy)void(^ colorBlock) (UIColor*color);
@property(nonatomic,strong)UILabel*lab1;
@end
********************************************************************
- (void)viewDidLoad {
[superviewDidLoad];
LTButton* btn = [[LTButtonalloc]initWithFrame:CGRectMake(0,60,100,100)];
[btnsetBackgroundColor:[UIColorredColor]];
[self.viewaddSubview:btn];
__weaktypeof(self) weakSelf =self;
[btnaddEvent:UIControlEventTouchUpInsideBlock:^(UIButton* blockBtn) {
[blockBtnsetTitle:@"wanghu"forState:UIControlStateNormal];
weakSelf.view.backgroundColor= [UIColorredColor];
}];
LTButton* btn2 = [[LTButtonalloc]initWithFrame:CGRectMake(150,64,100,100)];
[self.viewaddSubview:btn2];
[btn2setBackgroundColor:[UIColorblueColor]];
UILabel* btn3 = [[UILabelalloc]initWithFrame:CGRectMake(150,264,100,100)];
[self.viewaddSubview:btn3];
[btn3setBackgroundColor:[UIColorblueColor]];
void(^retBlock)(UILabel*) = [btn2returnBlock:^(UIButton* btnReturn) {
[btnReturnsetTitle:@"btn Return"forState:UIControlStateNormal];
[btnReturnsetBackgroundColor:[UIColororangeColor]];
}];
retBlock(btn3);
void(^block1)() = ^ {
NSLog(@"return nothing !");
};
block1();
//void无返回类型
void(^block2) (int) = ^(intaa) {
NSLog(@"return int aa == %D",aa);
};
block2(3);//调用block方法时,才回执行block里面的方法.
//返回类型block名称传入参数实现方法传入的参数
NSString*(^block3) (NSString*) = ^(NSString*str3) {
str3 =@"hahh";
returnstr3;
};
NSLog(@"%@",block3);
/////////////////////////
intx =5;
int(^block4)(int) = ^(inty) {
intz = x + y;//x值编译就确定为常量5,而不会受到外面x变量影响
returnz;
};
NSLog(@"%d,%d",x +=5,block4(5));
//x值先自增5 ,x = 10;然后执行block4里面的方法,参数值5, z = 5 + 5;
__blockintx2 =5;
int(^block5) (int) = ^(inty){
intz = x2 + y;//x2受到外面x2变量影响
returnz;
};
NSLog(@"%d,%d",x2 +=5,block5(5));
//x2值先自增5 ,x2 = 10;然后执行block5里面的方法,参数值5, z = 10 + 5;
self.view.backgroundColor= [UIColorwhiteColor];
__weaktypeof(self.lab1) weakLab =self.lab1;
self.colorBlock= ^(UIColor* color){
__strongtypeof(weakLab) storLab = weakLab;
storLab.text=@"ahhahah";
};
/*
Block为什么用copy(或者strong也行)修饰?
默认情况下,block是存档在栈中,可能被随时回收,通过copy操作可以使其在堆中保留一份,相当于一直强引用着,因此如果block中用到self时,需要将其弱化,通过__weak或者__unsafe_unretained.以下是示例代码及其说明,读者可以试着打印出不同情况下block的内存情况
在调用时需要把Block先赋值给本地变量,以防止Block突然改变。因为如果不这样的话,即便是先判断了Block属性不为空,在调用之前,一旦另一个线程把Block属性设空了,程序就会crash,如下代码:
if (self.myBlock)
{
//此时,走到这里,self.myBlock可能被另一个线程改为空,造成crash
//注意:atomic只会确保myBlock的原子性,这种操作本身还是非线程安全的
self.myBlock(123);
}
所以正确的代码是(ARC):
MyBlockType block = self.myBlock;
//block现在是本地不可变的
if (block)
{
block(123);
}
*/
}
-(void)onTapBtn:(UIButton*)btn{
}
******************************************************************************
#import"ViewController.h"
#import"LTPerson.h"
#import"LTDog.h"
#import"BlocksKit.h"
#import"BlocksKit+UIKit.h"
#import
#import
@interfaceViewController ()
@property(nonatomic,weak)IBOutletUILabel *label1;
@property(nonatomic,weak)IBOutletUILabel *label2;
@property(nonatomic,weak)IBOutletNSLayoutConstraint *label1Con;
@property(nonatomic,strong) NSTimer* timer;
@property(nonatomic,strong)NSThread *threadloop;
@property(nonatomic,strong) UIImageView *gcdGroupImageV;
@property(nonatomic,strong) UIImageView *imageViewPerform;
//动画
@property(nonatomic,strong) UIImageView *imageViewAnimation;
@property(nonatomic,assign)doubleangle;
@property(nonatomic,strong)UITableView* tableView;
@end
NSString* textC(NSString* ,NSString*);
NSString* textC(NSString* str1,NSString* str2){
return[NSStringstringWithFormat:@"%@%@",str1,str2];
}
@implementationViewController
- (void)viewDidLoad {
[superviewDidLoad];
[selftestAnimation];
}
#pragma mark -常用动画
- (void)testAnimation {
self.imageViewAnimation = [[UIImageView alloc]initWithFrame:CGRectMake(100,100,100,100)];
self.imageViewAnimation.image = [UIImage imageNamed:@"ANIMALL"];
[self.view addSubview:self.imageViewAnimation];
self.imageViewAnimation.alpha =1.0;
//设置圆角考虑性能参考:https://github.com/panghaijiao/HJCornerRadius
self.imageViewAnimation.layer.cornerRadius =10.0;
//动画参考:http://zhangmingwei.iteye.com/blog/2101782
//1图像左右抖动
[selftestshakeAnimation];
//2中心旋转动画两种方法
self.angle =0;
[selftestTransform];
[selftestTransform2];
// 3.某一点旋转
[selftestTransform3];
// 4.关键帧动画(指定路径动画)
[selftestTransform4];
// 5.翻转动画
//self animationEaseIn:
}
#pragma mark -图像左右抖动
- (void)testshakeAnimation {
CAKeyframeAnimation *shakeAnim = [CAKeyframeAnimation animation];
shakeAnim.keyPath =@"transform.translation.x";
shakeAnim.duration =0.15;
CGFloat delta =10;
shakeAnim.values =@[@0,@(-delta),@(delta),@0];
shakeAnim.repeatCount =12;
[self.imageViewAnimation.layer addAnimation:shakeAnim forKey:nil];
}
#pragma mark -旋转动画-设置旋转角度
- (void)testTransform {
CGAffineTransform endAngle = CGAffineTransformMakeRotation(self.angle * (M_PI /180.0));
[UIView animateWithDuration:0.5delay:0.1options:UIViewAnimationOptionCurveLinear animations:^{
//UIViewAnimationOptionCurveLinear :动画匀速执行,默认值
self.imageViewAnimation.transform = endAngle;
} completion:^(BOOLfinished) {
if(self.angle >720) {
self.angle =self.angle -360.0;
}
self.angle +=10;
[selftestTransform];
}];
}
#pragma mark -旋转动画2 -以z轴为中心,重复旋转
- (void)testTransform2 {
CABasicAnimation* rotationAnimation;
rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
rotationAnimation.toValue = [NSNumber numberWithFloat: M_PI *2.0];
rotationAnimation.duration =0.8;//
rotationAnimation.cumulative =YES;
rotationAnimation.repeatCount =1000;
[self.imageViewAnimation.layer addAnimation:rotationAnimation forKey:@"rotationAnimation"];
}
#pragma mark -旋转动画3 -以某一点为中心,重复旋转
- (void)testTransform3 {
CGAffineTransform endAngle = CGAffineTransformMakeRotation(self.angle * (M_PI /180.0));
[UIView animateWithDuration:0.5delay:0.1options:UIViewAnimationOptionCurveLinear animations:^{
//UIViewAnimationOptionCurveLinear :动画匀速执行,默认值
self.imageViewAnimation.layer.anchorPoint = CGPointMake(1,1);//以右下角为原点转,(0,0)是左上角转,(0.5,0,5)心中间转,其它以此类推
self.imageViewAnimation.transform = endAngle;
} completion:^(BOOLfinished) {
if(self.angle >720) {
self.angle =self.angle -360.0;
}
self.angle +=10;
[selftestTransform3];//重复旋转
}];
}
#pragma mark -旋转动画4 -关键帧动画(路径动画)
- (void)testTransform4 {
CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
CGMutablePathRef aPath = CGPathCreateMutable();
CGPathMoveToPoint(aPath,nil,20,20);
CGPathAddCurveToPoint(aPath,nil,160,30,220,220,240,420);
animation.path = aPath;
animation.autoreverses =YES;
animation.duration =2;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
animation.rotationMode =@"auto";
[self.imageViewAnimation.layer addAnimation:animation forKey:@"position"];
}
#pragma mark -翻转动画5 -
+ (void)animationEaseIn:(UIView *)view {
CATransition *animation = [CATransition animation];
[animation setDuration:0.35f];
[animation setType:kCATransitionFade];
[animation setFillMode:kCAFillModeForwards];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]];
[view.layer addAnimation:animation forKey:nil];
}
#pragma mark -线程间通信常用方法
- (void)testPerformSelector {
//转到后台下载
[selfperformSelectorInBackground:@selector(backgroundDownd) withObject:nil];
}
- (void)backgroundDownd {
NSURL *urlstr=[NSURL URLWithString:@"fdsf"];
NSData *data=[NSData dataWithContentsOfURL:urlstr];//这一行操作会比较耗时
UIImage *image=[UIImage imageWithData:data];
//回到主线程中设置图片
//第一种方式:调用settingImage:方法设置图片
//[self performSelectorOnMainThread:@selector(settingImage:) withObject:image waitUntilDone:NO];
//第二种方式
//[self performSelector:@selector(setImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:NO];
//第三种方式:直接给imageview设置
[self.imageViewPerform performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO];
}
- (void)settingImage:(UIImage *)image {
self.imageViewPerform.image = image;
}
#pragma mark -对象加锁
- (void)testQueueConfict {
NSMutableArray *mutArray = [[NSMutableArray alloc]initWithObjects:@"a",@"b",@"c",@"d",nil];
//对对象进行加锁防止其他线程同时修改
//注意:锁定1份代码只用1把锁,用多把锁是无效的
//或者锁定一份代码:@synchronized (self) {}
@synchronized(mutArray) {
[mutArray removeObject:@"b"];
}
}
#pragma mark -调试函数耗时的利器
- (void)testAbsoluteTime {
//调试函数耗时的利器CFAbsoluteTimeGetCurrent
CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
// do something
CFAbsoluteTime end = CFAbsoluteTimeGetCurrent();
NSLog(@"time cost: %0.3f", end - start);
}
#pragma mark - GCD常用方法
- (void)testGCD {
//串行
dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL);
//并行
dispatch_queue_t concurrent = dispatch_queue_create("concurrent", DISPATCH_QUEUE_CONCURRENT);
//同步串行(并行效果一样) (主线程)
dispatch_sync(serialQueue, ^{
for(inti =0; i <10; i ++) {
NSLog(@"同步串行1");
}
});
dispatch_sync(serialQueue, ^{
for(inti =0; i <10; i ++) {
NSLog(@"同步串行2");
}
});
//异步串行(子线程一个)
dispatch_sync(concurrent, ^{
});
//异步并行(子线程可多个)
dispatch_async(concurrent, ^{
});
/////////////////////////////////////////////////////////////////////////////////
//简单实例:实现合并图片功能
__blockUIImage *image1;
__blockUIImage *image2;
dispatch_async(dispatch_get_global_queue(0,0), ^{
NSURL *url = [NSURL URLWithString:@"https://"];
image1 = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
});
dispatch_async(dispatch_get_global_queue(0,0), ^{
NSURL *url = [NSURL URLWithString:@"https://"];
image2 = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
});
//创建队列组
dispatch_group_t group1 = dispatch_group_create();
//创建全局队列组
dispatch_group_async(group1, dispatch_get_global_queue(0,0), ^{
NSURL *url = [NSURL URLWithString:@"https://"];
image1 = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
NSURL *url2 = [NSURL URLWithString:@"https://"];
image2 = [UIImage imageWithData:[NSData dataWithContentsOfURL:url2]];
});
__weaktypeof(self)weakSelf =self;
//组队列任务执行完毕通知
dispatch_group_notify(group1, dispatch_get_global_queue(0,0), ^{
//合并图片
UIGraphicsBeginImageContext(CGSizeMake(100,100));//开启上下文绘制位置
[image1 drawInRect:CGRectMake(0,0,100,50)];//绘制上半部分
[image2 drawInRect:CGRectMake(0,50,100,50)];//绘制下半部分
image1 =nil;//清空
image2 =nil;
UIImage *imageCombine = UIGraphicsGetImageFromCurrentImageContext();//保存合并图片到对象
UIGraphicsEndImageContext();//关闭上下文
__strongtypeof(weakSelf)strongSelf = weakSelf;//内部强引用,防止被提前释放
//主线程执行更新
dispatch_async(dispatch_get_main_queue(), ^{
strongSelf.gcdGroupImageV.image = imageCombine;
});
});
}
#pragma mark - Masonry简单使用
- (void)testMasonry19 {
UIView *view1= [[UIView alloc]init];
view1.backgroundColor = [UIColor redColor];
[self.view addSubview:view1];
[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.mas_equalTo(CGSizeMake(200,300));
make.center.equalTo(self.view);
}];
UIView *view2 = [[UIView alloc]init];
view2.backgroundColor = [UIColor orangeColor];
[view1 addSubview:view2];
[view2 mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(view1.mas_centerY);
make.left.equalTo(view1.mas_left).with.offset(10);
make.right.equalTo(view1.mas_centerX).with.offset(-10);
make.top.equalTo(view1.mas_top).with.offset(25);
make.bottom.equalTo(view1.mas_bottom).with.offset(-53);
}];
}
#pragma mark - Realm的常见使用方法
- (void)testRealm {
// Do any additional setup after loading the view, typically from a nib.
//存储对象
LTPerson* person1 = [[LTPerson alloc]init];
person1.name =@"王虎";
person1.card =@"442398723049012-4";
LTDog* dog1 = [[LTDog alloc]init];
dog1.age =@"3";
dog1.name =@"小宏";
LTDog* dog2 = [[LTDog alloc]init];
dog2.age =@"1";
dog2.name =@"小黑";
[person1.dogs addObject:dog1];
[person1.dogs addObject:dog2];
LTPerson* person2 = [[LTPerson alloc]init];
person2.name =@"SB";
person2.card =@"442398723049012-4";
LTDog* dog11 = [[LTDog alloc]init];
dog1.age =@"3";
dog1.name =@"小宏";
LTDog* dog12 = [[LTDog alloc]init];
dog2.age =@"1";
dog2.name =@"小黑";
[person2.dogs addObject:dog11];
[person2.dogs addObject:dog12];
/*
1
@interface LTDog : RLMObject
@property NSString* age;
@property NSString* name;
@end
RLM_ARRAY_TYPE(LTDog)
注意:
(1) @property NSString *name;
设置属性不需要nonatomic, atomic, strong, copy, weak等修饰符
(2)要用Realm的宏“RLM_ARRAY_TYPE“来定义“RLMArray”这个类型
*/
//2存储对象
RLMRealm *realm = [RLMRealm defaultRealm];
[realm beginWriteTransaction];
[realm addObject:person1];
[realm addObject:person1];
[realm commitWriteTransaction];
//3取出对象
NSMutableArray* doglist = [NSMutableArray array];
RLMResults *persons = [LTPerson objectsWhere:@"name = '王虎'"];
for(LTPerson* personinpersons) {
RLMResults * dogs = [person.dogs objectsWhere:@"name = '小黑'"];
[doglist addObject:dogs];
}
//查询过滤其它字符设置:http://www.jianshu.com/p/52a9f84b158f
RLMResults *sortedDogs = [LTDog objectsWhere:@"color = 'tan' AND name BEGINSWITH 'B'"];
//4获取保存在内存中的realm数据库
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
config.inMemoryIdentifier =@"MyInMemoryRealm";
RLMRealm *realmMemory = [RLMRealm realmWithConfiguration:config error:nil];
// 5数据更新通知->更新UI
/*
realm通知
假设这样的一个场景,当数据改变时我们需要更新UI,那怎样才知道有数据改动了呢?而且更新UI的操作又需要在主线线程中,而一般DB操作我们会单独启一个IO线程,那该如何是好呢?
别急,Realm为每个数据库realm对象都设置了一个数据改变时的通知:
文/CZ_iOS(作者)
原文链接:http://www.jianshu.com/p/52a9f84b158f
著作权归作者所有,转载请联系作者获得授权,并标注“作者”。
*/
// 5.1 realm整个数据通知
RLMNotificationToken *token = [[RLMNotificationToken alloc]init];
token = [realm addNotificationBlock:^(NSString *notification, RLMRealm * realm) {
RLMRealm * realmGet = realm;//获取到通知返回的数据
//do something
[selfupdateUI:realmGet];//把返回的数据用于更新界面
}];
//如果不需要监听了
[token stop];
// 5.2数据对象进行监控[这里虽然说是数据对象,实际是是Realm提供的容器类型,比如:RLMResult、RLMArray、RLMLinkingObjectes]
RLMArray *rlmarr = [RLMArray init];
token = [rlmarr addNotificationBlock:^(RLMArray *_Nullablearray, RLMCollectionChange *_Nullablechanges, NSError *_Nullableerror) {
}];
// 6版本兼容问题旧->新
/*
新版本修改模型属性并新增属性的情况:线上用户本地数据如何兼容加载?
1之前:
@property NSString *name;
2之后:
@property NSString *firstName;
@property NSString *lastName;
3解决原理:
将老数据的name转换成"firstName",而lastName则置为"None"。
然后在用这个RLMRealmConfiguration创建realm就可以了。
*/
RLMRealmConfiguration *config2 = [RLMRealmConfiguration defaultConfiguration];
config.schemaVersion =1;
config.migrationBlock = ^(RLMMigration *migration, uint64_t oldSchemaVersion) {
if(oldSchemaVersion <1) {
[migration enumerateObjects:LTPerson.className
block:^(RLMObject *oldObject, RLMObject *newObject) {
newObject[@"firstName"] = oldObject[@"name"];
newObject[@"lastName"] =@"Node";
}];
}
};
[RLMRealmConfiguration setDefaultConfiguration:config2];
// 7数据加密
/*1 Realm提供了AES-256加密算法并用SHA2进行密文校验,使用起来也非常简单,只要生成一个256bit的秘钥(当然你要保护好这个秘钥,比如从安全的服务器信道传下来),然后将其给到RLMRealmConfiguration,在用这个RLMRealmConfiguration创建realm就可以了
2添加Security.framework框架
3用了Security.framework里面的SecRandomCopyBytes得到一串随机数,作为秘钥,然后用这个秘钥给到RLMRealmConfiguration创建realm在行使用,这样数据存储时就会被加密了。
*/
uint8_tbuffer[64];
intrandInt =SecRandomCopyBytes(kSecRandomDefault,64, buffer);
NSData*keyData = [[NSDataalloc]initWithBytes:bufferlength:sizeof(buffer)];
NSLog(@"SecRandomCopyBytes = %d",randInt);
RLMRealmConfiguration *configuration = [RLMRealmConfiguration defaultConfiguration];
configuration.encryptionKey= keyData;
RLMRealm *realm3 = [RLMRealm realmWithConfiguration:configuration error:nil];
}
//更新界面
- (void)updateUI:(RLMRealm *)realm {
}
#pragma mark - tableview delegete
-(NSInteger)numberOfSectionsInTableView:(UITableView*)tableView{
return1;
}
-(NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section{
return30;
}
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath{
UITableViewCell* cell = [tableViewdequeueReusableCellWithIdentifier:@"cell"];
if(cell ==nil) {
cell = [[UITableViewCellalloc]initWithStyle:UITableViewCellStyleDefaultreuseIdentifier:@"cell"];
}
cell.textLabel.text=@"test";
returncell;
}
@end
******************************runtime***********************************************
#import"UILabel+runtimeLab.h"
#import
@implementationUILabel (runtimeLab)
#pragma mark-参考地址:http://www.jianshu.com/p/07b6c4a40a90
#pragma mark -添加公共属性->关联对象
-(void)setName:(NSString*)name {
//这里使用方法的指针地址作为唯一的key
objc_setAssociatedObject(self,@selector(name), name,OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(NSString*)name {
returnobjc_getAssociatedObject(self,@selector(name));
}
#pragma mark - Method Swizzling方法交换
/*
自己使用过例子:
使用场景,在iOS7中如果viewdidappear还没有完成,就立刻执行push或者pop操作会crash,见我之前写过的一篇文章iOS7中的pop导致的crash
解决方案就是利用method swizzing,将系统的viewdidappear替换为自己重写的sofaViewDidAppear
*/
+(void)load {// load系统运行该类加载初始化时就会调用
staticdispatch_once_tonceToken;
dispatch_once(&onceToken, ^{
Class selfClass =object_getClass([selfclass]);
SELoriSEL =@selector(setTextColor:);
MethodoriMoth =class_getInstanceMethod(selfClass, oriSEL);
SELcurSEL =@selector(mysetTextColor:);
MethodcurMoth =class_getInstanceMethod(selfClass, curSEL);
BOOLaddSucc =class_addMethod(selfClass, oriSEL,method_getImplementation(curMoth),method_getTypeEncoding(curMoth));
if(addSucc) {
class_replaceMethod(selfClass, curSEL,method_getImplementation(oriMoth),method_getTypeEncoding(oriMoth));
}else{
method_exchangeImplementations(oriMoth, curMoth);
}
});
}
//该类第一次被调用时调用该方法
+(void)initialize {
}
#pragmamark - json->model
- (instancetype)initWithDict:(NSDictionary*)dict {
if(self= [selfinit]) {
//(1)获取类的属性及属性对应的类型
NSMutableArray* keys = [NSMutableArrayarray];
NSMutableArray* attributes = [NSMutableArrayarray];
/*
*例子
* name = value3 attribute = T@"NSString",C,N,V_value3
* name = value4 attribute = T^i,N,V_value4
*/
unsignedintoutCount;
objc_property_t* properties =class_copyPropertyList([selfclass], &outCount);
for(inti =0; i < outCount; i ++) {
objc_property_tproperty = properties[i];
//通过property_getName函数获得属性的名字
NSString* propertyName = [NSStringstringWithCString:property_getName(property)encoding:NSUTF8StringEncoding];
[keysaddObject:propertyName];
//通过property_getAttributes函数可以获得属性的名字和@encode编码
NSString* propertyAttribute = [NSStringstringWithCString:property_getAttributes(property)encoding:NSUTF8StringEncoding];
[attributesaddObject:propertyAttribute];
}
//立即释放properties指向的内存
free(properties);
//(2)根据类型给属性赋值setValue
for(NSString* keyinkeys) {
if([dictvalueForKey:key] ==nil)continue;
[selfsetValue:[dictvalueForKey:key]forKey:key];
}
}
returnself;
}
#pragma mark -一键序列化实现NSCoding自动归档和解档
/*
原理描述:用runtime提供的函数遍历Model自身所有属性,并对属性进行encode和decode操作。
核心方法:在Model的基类中重写方法:
获得属性:Ivar * ivars = class_copyIvarList([self class], &outCount);
NSString * key = [NSString stringWithUTF8String:ivar_getName(ivar)];
*/
- (id)initWithCoder:(NSCoder*)aDecoder {
if(self= [superinit]) {
unsignedintoutCount;
Ivar* ivars =class_copyIvarList([selfclass], &outCount);
for(inti =0; i < outCount; i ++) {
Ivarivar = ivars[i];
NSString* key = [NSStringstringWithUTF8String:ivar_getName(ivar)];
[selfsetValue:[aDecoderdecodeObjectForKey:key]forKey:key];
}
}
returnself;
}
- (void)encodeWithCoder:(NSCoder*)aCoder {
unsignedintoutCount;
Ivar* ivars =class_copyIvarList([selfclass], &outCount);
for(inti =0; i < outCount; i ++) {
Ivarivar = ivars[i];
NSString* key = [NSStringstringWithUTF8String:ivar_getName(ivar)];
[aCoderencodeObject:[selfvalueForKey:key]forKey:key];
}
}
@end
***********************************RAC**************************************************
1
//textFild的文字更改监听
[[self.textFild rac_textSignal] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
2
//点击事件:监听了textFild的UIControlEventEditingChanged事件,button点击事件也是
[[self.textFild rac_signalForControlEvents:UIControlEventEditingChanged] subscribeNext:^(id x){
NSLog(@"改变了");
}];
3
//给我们的某个label添加一个手势动作,我们也可以用简单的RAC代码完成
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init];
[[tap rac_gestureSignal] subscribeNext:^(id x) {
NSLog(@"tap");
}];
[self.view addGestureRecognizer:tap];
4
//代理: AlertView代理也有简化的代码。
[[alertView rac_buttonClickedSignal] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
5
//通知:发送名为postdata的通知并传送一个数组dataArray。
NSMutableArray *dataArray = [[NSMutableArray alloc] initWithObjects:@"1", @"2", @"3", nil];
[[NSNotificationCenter defaultCenter] postNotificationName:@"postData" object:dataArray];
//而在接受的页面我们需要增加观察者并接受数组,这时我们的RAC就派上用场了。
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:@"postData" object:nil] subscribeNext:^(NSNotification *notification) {
NSLog(@"%@", notification.name);
NSLog(@"%@", notification.object);
}];
6
//RAC中得KVO大部分都是宏定义,所以代码异常简洁,简单来说就是RACObserve(TARGET, KEYPATH)这种形式,TARGET是监听目标,KEYPATH是要观察的属性值,这里举一个很简单的例子,如果UIScrollView滚动则输出success。
UIScrollView *scrolView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 200, 400)];
scrolView.contentSize = CGSizeMake(200, 800);
scrolView.backgroundColor = [UIColor greenColor];
[self.view addSubview:scrolView];
[RACObserve(scrolView, contentOffset) subscribeNext:^(id x) {
NSLog(@"success");
}];
****************************************函数式编程***********************************************
.h文件
@interface SQLTool : NSObject
//这里不需要了,放到.m中去
//@property (nonatomic, strong, readonly) NSString *sql;
//添加这个方法,参数是一个block,传递一个SQLTool的实例
+ (NSString *)makeSQL:(void(^)(SQLTool *tool))block;
//定义select的block
typedef SQLTool *(^Select)(NSArray *columns);
@property (nonatomic, strong, readonly) Select select;
...
@end
.m文件
@interface SQLTool ()
//用于保存拼接后的SQL
@property (nonatomic, strong) NSString *sql;
@end
@implementation SQLTool
+ (NSString *)makeSQL:(void(^)(SQLTool *tool))block {
if (block) {
SQLTool *tool = [[SQLTool alloc] init];
block(tool);
return tool.sql;
}
return nil;
}
- (Select)select {
return ^(NSArray *columns) {
if (columns.count > 0) {
self.sql = [NSString stringWithFormat:@"SELECT %@", [columns componentsJoinedByString:@","]];
} else {
self.sql = @"SELECT *";
}
//这里将自己返回出去
return self;
}
}
...
@end
然后调用时是这样的:
NSString *sql = [SQLTool makeSQL:^(SQLTool * tool) {
tool.select(nil).from(@"table").where(@"columnA = 1");
}];
****************************************链式编程***********************************************
.h文件
//定义select的block
typedef SQLTool *(^Select)(NSArray *columns);
@property (nonatomic, strong, readonly) Select select;
.m文件
- (Select)select {
return ^(NSArray *columns) {
if (columns.count > 0) {
self.sql = [NSString stringWithFormat:@"SELECT %@", [columns componentsJoinedByString:@","]];
} else {
self.sql = @"SELECT *";
}
//这里将自己返回出去
return self;
}
}
最终实现的目标是以下类似的:
SQLTool *tool = [[SQLTool alloc] init];
NSString*testSQL1 = tool.select(nil).from(@"Table").orderBy(@"Column DESC").sql;
****************SQL常用增删改查语句********************************************************************
1增
1.1【插入单行】
insert [into] <表名> (列名) values (列值)
例:insert into Strdents (姓名,性别,出生日期) values ('开心朋朋','男','1980/6/15')
1.2【将现有表数据添加到一个已有表】
insert into <已有的新表> (列名) select <原表列名> from <原表名>
例:insert into tongxunlu ('姓名','地址','电子邮件')
select name,address,email
from Strdents
1.3【直接拿现有表数据创建一个新表并填充】
select <新建表列名> into <新建表名> from <源表名>
例:select name,address,email into tongxunlu from strdents
1.4【使用union关键字合并数据进行插入多行】
insert <表名> <列名> select <列值> tnion select <列值>
例:insert Students (姓名,性别,出生日期)
select '开心朋朋','男','1980/6/15' union(union表示下一行)
select '蓝色小明','男','19**/**/**'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2删
2.1【删除<满足条件的>行】
delete from <表名> [where <删除条件>]
例:delete from a where name='开心朋朋'(删除表a中列值为开心朋朋的行)
2.2【删除整个表】
truncate table <表名>
truncate table tongxunlu
注意:删除表的所有行,但表的结构、列、约束、索引等不会被删除;不能用语有外建约束引用的表
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3改
update <表名> set <列名=更新值> [where <更新条件>]
例:update tongxunlu set 年龄=18 where 姓名='蓝色小名'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4查
4.1``精确(条件)查询
select <列名> from <表名> [where <查询条件表达试>] [order by <排序的列名>[asc或desc]]
4.1.1【查询所有数据行和列】
例:select * from a
说明:查询a表中所有行和列
4.1.2【查询部分行列--条件查询】
例:select i,j,k from a where f=5
说明:查询表a中f=5的所有行,并显示i,j,k3列
4.1.3【在查询中使用AS更改列名】
例:select name as 姓名 from a where xingbie='男'
说明:查询a表中性别为男的所有行,显示name列,并将name列改名为(姓名)显示
4.1.4【查询空行】
例:select name from a where email is null
说明:查询表a中email为空的所有行,并显示name列;SQL语句中用is null或者is not null来判断是否为空行
4.1.5【在查询中使用常量】
例:select name, '唐山' as 地址 from Student
说明:查询表a,显示name列,并添加地址列,其列值都为'唐山'
4.1.6【查询返回限制行数(关键字:top percent)】
例1:select top 6 name from a
说明:查询表a,显示列name的前6行,top为关键字
例2:select top 60 percent name from a
说明:查询表a,显示列name的60%,percent为关键字
4.1.7【查询排序(关键字:order by , asc , desc)】
例:select name
from a
where chengji>=60
order by desc
说明:查询a表中chengji大于等于60的所有行,并按降序显示name列;默认为ASC升序
4.2``模糊查询
4.2.1【使用like进行模糊查询】
注意:like运算副只用于字符串,所以仅与char和varchar数据类型联合使用
例:select * from a where name like '赵%'
说明:查询显示表a中,name字段第一个字为赵的记录
4.2.2【使用between在某个范围内进行查询】
例:select * from a where nianling between 18 and 20
说明:查询显示表a中nianling在18到20之间的记录
4.2.3【使用in在列举值内进行查询】
例:select name from a where address in ('北京','上海','唐山')
说明:查询表a中address值为北京或者上海或者唐山的记录,显示name字段
4.3``.分组查询
4.3.1【使用group by进行分组查询】
例:select studentID as 学员编号,AVG(score) as 平均成绩 (注释:这里的score是列名)
from score (注释:这里的score是表名)
group by studentID
说明:在表score中查询,按strdentID字段分组,显示strdentID字段和score字段的平均值;select语句中只允许被分组的列和为每个分组返回的一个值的表达式,例如用一个列名作为参数的聚合函数
4.3.2【使用having子句进行分组筛选】
例:select studentID as 学员编号,AVG(score) as 平均成绩 (注释:这里的score是列名)
from score (注释:这里的score是表名)
group by studentID
having count(score)>1
说明:接上面例子,显示分组后count(score)>1的行,由于where只能在没有分组时使用,分组后只能使用having来限制条件。
4.4``.多表联接查询
4.4.1内联接
4.4.1.1【在where子句中指定联接条件】
例:select a.name,b.chengji
from a,b
where a.name=b.name
说明:查询表a和表b中name字段相等的记录,并显示表a中的name字段和表b中的chengji字段
4.4.1.2【在from子句中使用join⋯on】
例:select a.name,b.chengji
from a inner join b
on (a.name=b.name)
说明:同上
4.4.2外联接
4.4.2.1【左外联接查询】
例:select s.name,c.courseID,c.score
from strdents as s
left outer join score as c
on s.scode=c.strdentID
说明:在strdents表和score表中查询满足on条件的行,条件为score表的strdentID与strdents表中的sconde相同
4.4.2.2【右外联接查询】
例:select s.name,c.courseID,c.score
from strdents as s
right outer join score as c
on s.scode=c.strdentID
说明:在strdents表和score表中查询满足on条件的行,条件为strdents表中的sconde与score表的strdentID相同