iOS笔记-练习代码(三)

***********单例**************************************

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相同

你可能感兴趣的:(iOS笔记-练习代码(三))