2016-03-04 09:22:19 xingjie1006 阅读数 382

App内使用代码退出程序

- (void)configUI{
    UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"提示" message:@"" delegate:self cancelButtonTitle:@"cancel" otherButtonTitles:@"Exit", nil];
    [alert show];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
    NSLog(@"%ld",buttonIndex);
    if (buttonIndex == 1) {
        [self exitApp];
    }
}

- (void)exitApp{//退出App
    UIWindow *window = [UIApplication sharedApplication].delegate.window;//获得窗口
    [UIView animateWithDuration:1.0f animations:^{
        window.alpha = 0;
        window.frame = CGRectMake(SCREEN_WIDTH/2, window.bounds.size.width, 0, 0);
    } completion:^(BOOL finished) {
        exit(0);//动画完毕退出App
    }];
}
2016-08-19 11:57:00 u014220518 阅读数 5506

前言

iOS开发更新APP我觉得是比较坑的就是审核时间比较长,审核比较严,对于刚入行的小伙伴来说,雷区比较多;所以热更新是比较重要的;

大家也许会发现我们常用的QQ现在下来也就一百多兆,但是用了几个月后发现QQ在手机上占有一个多G的内存,特别是手机内存比较小的小伙伴,这是因为你在使用过程中,有一些功能是你下载下来的;

创建Framework

1.新建项目

新建一个Cocoa Touch Framework项目,然后在这个项目里面写你的新的功能,比如我创建了一个控制器,在控制器里面加载一张图和一个label;

<span style="font-size:18px;">- (void)uiConfig{
    self.title = @"这是功能2";
    
    UIImageView *imageView = [[UIImageView alloc]init];
    imageView.frame = CGRectMake(0, 0, ScreenWidth, ScreenHeight);
    NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://img4.duitang.com/uploads/item/201405/31/20140531174207_hH5u4.thumb.700_0.jpeg"]];
    imageView.image = [UIImage imageWithData:data];
    [self.view addSubview:imageView];
    
    UILabel *label = [[UILabel alloc]init];
    label.backgroundColor = [UIColor clearColor];
    label.frame = CGRectMake(0, (ScreenHeight - 100)/2, ScreenWidth, 100);
    label.numberOfLines = 0;
    label.text = @"这是功能2这是功能2这是功能2这是功能2这是功能2这是功能2这是功能2这是功能2这是功能2这是功能2这是功能2这是功能2这是功能2这是功能2这是功能2";
    [self.view addSubview:label];
}</span>

2.添加Aggregate

在TARGETS里面新建一个Aggregate

 

3.添加Run Script脚本

4.脚本源码

# Sets the target folders and the final framework product.
# 如果工程名称和Framework的Target名称不一样的话,要自定义FMKNAME
# 例如: FMK_NAME = "MyFramework"
FMK_NAME=${PROJECT_NAME}
# Install dir will be the final output to the framework.
# The following line create it in the root folder of the current project.
INSTALL_DIR=${SRCROOT}/Products/${FMK_NAME}.framework
# Working dir will be deleted after the framework creation.
WRK_DIR=build
DEVICE_DIR=${WRK_DIR}/Release-iphoneos/${FMK_NAME}.framework
SIMULATOR_DIR=${WRK_DIR}/Release-iphonesimulator/${FMK_NAME}.framework
# -configuration ${CONFIGURATION}
# Clean and Building both architectures.
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphoneos clean build
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphonesimulator clean build
# Cleaning the oldest.
if [ -d "${INSTALL_DIR}" ]
then
rm -rf "${INSTALL_DIR}"
fi
mkdir -p "${INSTALL_DIR}"
cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/"
# Uses the Lipo Tool to merge both binary files (i386 + armv6/armv7) into one Universal final product.
lipo -create "${DEVICE_DIR}/${FMK_NAME}" "${SIMULATOR_DIR}/${FMK_NAME}" -output "${INSTALL_DIR}/${FMK_NAME}"
rm -r "${WRK_DIR}"
open "${INSTALL_DIR}"

 

5.运行打包

运行工程,将生成的framework包压缩zip,然后上传服务器;

例如:http://7xqdun.com1.z0.glb.clouddn.com/FunctionZFJ1.framework.zip

创建项目

在项目中我们主要是下载和读取framework包;我们先要获取功能列表,在此我在本地写了一个功能列表,大家如果用得到可以将功能列表存放在服务器上;

1.创建功能列表数据

我添加了四个功能模块,存在NSUserDefaults里面;其中功能1和功能2有下载地址,其他的没有;功能1是个NSObject,功能2直接是一个控制器;

isopen:1表示打开,0表示关闭;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    
    //添加假的功能列表
    NSArray *functionList = [USER_DEFAULT objectForKey:@"functionList"];
    if(functionList==nil || functionList.count==0){
        NSArray *titleArr  = @[@"功能1",@"功能2",@"功能3",@"功能4"];
        NSArray *className = @[@"HotUpdateControl",@"ZFJViewController",@"",@""];
        NSArray *classType = @[@"NSObject",@"UIViewController",@"",@""];
        NSArray *downUrl   = @[
                               @"http://7xqdun.com1.z0.glb.clouddn.com/HotMudel.framework.zip",
                               @"http://7xqdun.com1.z0.glb.clouddn.com/FunctionZFJ1.framework.zip",
                               @"",
                               @""];
        NSMutableArray *functionArr = [[NSMutableArray alloc]init];
        for (int i = 0; i<titleArr.count; i++) {
            NSMutableDictionary *dict = [[NSMutableDictionary alloc]init];
            [dict setObject:titleArr[i] forKey:@"name"];
            [dict setObject:className[i] forKey:@"classname"];
            [dict setObject:classType[i] forKey:@"classtype"];
            [dict setObject:@(i) forKey:@"mid"];
            [dict setObject:@"0" forKey:@"isopen"];//0 未开启  1开启了
            [dict setObject:downUrl[i] forKey:@"downurl"];
            [functionArr addObject:dict];
        }
        [USER_DEFAULT setObject:functionArr forKey:@"functionList"];
        [USER_DEFAULT synchronize];
    }
    
    DynamicViewController *dvc = [[DynamicViewController alloc]init];
    UINavigationController *nvc = [[UINavigationController alloc]initWithRootViewController:dvc];
    self.window.rootViewController = nvc;
    
    return YES;
}

 

2.展示功能列表

在功能列表主要用于展示所有打开过的功能,也就是isopen为1的所有功能;

a.获取本地所有打开的数据,然后在tableview上显示

- (void)getDataBase{
    [self.dataArray removeAllObjects];
    NSArray *functionList = [USER_DEFAULT objectForKey:@"functionList"];
    for (NSDictionary *dict in functionList) {
        NSInteger isopen = [dict[@"isopen"] integerValue];
        if(isopen==1){
            [self.dataArray addObject:dict];
        }
    }
    [self.tableview reloadData];
}


b.点击对于的tableviewcell 的时候跳转对应的framework读取出来的方法

注意,我将不同的framework存放在不同的文件夹下,以mid作为区分;

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    NSDictionary *dict = self.dataArray[indexPath.row];
    //获取framework的路径名,我已mid区分
    NSString *destinationPath = [NSHomeDirectory() stringByAppendingString:[NSString stringWithFormat:@"/Documents/FunctionZFJ%@",dict[@"mid"]]];
    NSArray* arrFramework = [self getFilenamelistOfType:@"framework" fromDirPath:destinationPath];
    NSString *bundlePath = [NSString stringWithFormat:@"%@/%@",destinationPath,[arrFramework lastObject]];
    if (![[NSFileManager defaultManager] fileExistsAtPath:bundlePath]) {
        NSLog(@"文件不存在");
        return;
    }
    
    NSBundle *bundle = [NSBundle bundleWithPath:bundlePath];
    if (!bundle || ![bundle load]) {
        NSLog(@"bundle加载出错");
    }
    
    NSString *className = dict[@"classname"];
    NSString *classtype = dict[@"classtype"];
    
    Class loadClass = [bundle classNamed:className];
    if (!loadClass) {
        NSLog(@"获取失败");
        return;
    }
    
    if([classtype isEqualToString:@"NSObject"]){
        NSObject *bundleObj = [loadClass new];
        NSArray *arrVc = [bundleObj performSelector:@selector(getVcs)];
        TabController *tvc = [[TabController alloc]initwithVcArray:arrVc];
        [self.navigationController pushViewController:tvc animated:YES];
    }else if([classtype isEqualToString:@"UIViewController"]){
        UIViewController *uvc = (UIViewController *)[loadClass new];
        [self.navigationController pushViewController:uvc animated:YES];
    }
}

 

c.效果图

 

3.更多功能

在这里我们可以打开或者关闭某个功能;

a.获取所以功能,包括打开或者关闭状态的;然后在tableview上显示;

#pragma mark - 获取全部数据
- (void)getDataBase{
    [self.dataArray removeAllObjects];
    
    NSArray *functionList = [USER_DEFAULT objectForKey:@"functionList"];
    NSMutableArray *openYES = [[NSMutableArray alloc]init];
    NSMutableArray *openNO = [[NSMutableArray alloc]init];
    for (NSDictionary *dict in functionList) {
        NSMutableDictionary *muDict = [[NSMutableDictionary alloc]initWithDictionary:dict];
        NSInteger isopen = [muDict[@"isopen"] integerValue];
        if(isopen==1){
            //已经打开的功能
            [openYES addObject:muDict];
        }else{
            //没有打开的功能
            [openNO addObject:muDict];
        }
    }
    
    [self.dataArray addObject:openNO];
    [self.dataArray addObject:openYES];
    
    [self.tableview reloadData];
}


b.打开功能

打开某个功能就是下载对应的framework,把下载下来的zip包进行解压一下然后获取到framework,接着删除zip包,把framework放在对于的目录下;最后改变本地列表功能的状态;

#pragma mark - 开启某个功能 先下载数据
- (void)SSZipArchiveDataBaseWithDict:(NSMutableDictionary *)dict{
    NSString *requestURL = dict[@"downurl"];
    if(requestURL==nil || requestURL.length==0){
        self.progresslabel.text = [NSString stringWithFormat:@"%@-没有下载地址,不能开启!",dict[@"name"]];
        UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:@"没有下载地址,不能开启" preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction *sureBtn = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil];
        [alertController addAction:sureBtn];
        [self presentViewController:alertController animated:YES completion:nil];
        return;
    }
    //下载保存的路径
    NSString *savedPath = [NSHomeDirectory() stringByAppendingString:[NSString stringWithFormat:@"/Documents/FunctionZFJ%@.framework.zip",dict[@"mid"]]];
    AFHTTPRequestSerializer *serializer = [AFHTTPRequestSerializer serializer];
    NSMutableURLRequest *request = [serializer requestWithMethod:@"POST" URLString:requestURL parameters:nil error:nil];
    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]initWithRequest:request];
    [operation setOutputStream:[NSOutputStream outputStreamToFileAtPath:savedPath append:NO]];
    [operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
        float progress = (float)totalBytesRead / totalBytesExpectedToRead;
        self.progresslabel.text = [NSString stringWithFormat:@"%@下载进度:%.2f",dict[@"name"],progress];
    }];
    [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
        NSLog(@"下载成功");
        NSString *destinationPath = [NSHomeDirectory() stringByAppendingString:[NSString stringWithFormat:@"/Documents/FunctionZFJ%@",dict[@"mid"]]];
        //对下载下来的ZIP包进行解压
        BOOL isScu = [SSZipArchive unzipFileAtPath:savedPath toDestination:destinationPath];
        if(isScu){
            NSLog(@"解压成功");
            NSFileManager *fileMgr = [NSFileManager defaultManager];
            BOOL bRet = [fileMgr fileExistsAtPath:savedPath];
            if (bRet) {
                [fileMgr removeItemAtPath:savedPath error:nil];//解压成功后删除压缩包
            }
            [dict setValue:@"1" forKey:@"isopen"];
            [self updataBaseWithDict:dict];//解压成功后更新本地功能列表状态
        }else{
            NSLog(@"解压失败 --- 开启失败");
        }
        
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        NSLog(@"下载失败 --- 开启失败");
        
    }];
    [operation start];
}

更新本地数据

#pragma mark - 更新本地数据
- (void)updataBaseWithDict:(NSMutableDictionary *)dict{
    NSInteger mid = [dict[@"mid"] integerValue];
    NSMutableArray *functionList = [USER_DEFAULT objectForKey:@"functionList"];
    NSMutableArray *dataArr = [[NSMutableArray alloc]initWithArray:functionList];
    [dataArr replaceObjectAtIndex:mid withObject:dict];
    [USER_DEFAULT setObject:dataArr forKey:@"functionList"];
    BOOL isScu = [USER_DEFAULT synchronize];
    if(isScu){
        [self getDataBase];//重新获取数据 更新列表
        if(self.refreshData){
            self.refreshData();
        }
    }else{
        NSLog(@"c操作失败");
    }
}

 

c.关闭功能

关闭某个功能,也就是删除某个功能的framework,然后更改功能列表的状态;

#pragma mark - 关闭某个功能
- (void)delectFunctionZFJWithDict:(NSMutableDictionary *)dict{
    NSFileManager *fileMgr = [NSFileManager defaultManager];
    NSString *savedPath = [NSHomeDirectory() stringByAppendingString:[NSString stringWithFormat:@"/Documents/FunctionZFJ%@",dict[@"mid"]]];
    BOOL bRet = [fileMgr fileExistsAtPath:savedPath];
    if (bRet) {
        NSError *err;
        //关闭某个功能 就是删除本地的framework  然后修改本地功能状态
        BOOL isScu = [fileMgr removeItemAtPath:savedPath error:&err];
        if(isScu){
            [dict setValue:@"0" forKey:@"isopen"];
            [self updataBaseWithDict:dict];
        }else{
            NSLog(@"关闭失败");
        }
    }else{
        NSLog(@"关闭失败");
    }
}

 

d.效果图

 

源代码

在这里面有,两个framework的源代码,可项目的代码;

注意,如果有多个功能的framework,记住多个framework的命名在同一个功能里面不能重复,不然调取失败;

链接: http://download.csdn.net/detail/u014220518/9643039

效果图

 

转载请注明来源:http://blog.csdn.net/u014220518/article/details/52248803

 

2016-09-13 16:37:56 liaohongwei 阅读数 1016

第1章 欢迎来到iOS和Swift世界

  • 用户按下Home键,iOS就会返回主屏 幕,应用必须尽快保存一切内容并退出。如果没有在5秒之内保存必要的数据并放弃对系统资源的控制,无论是否已经完全保存,应用程序进程都会被终止。
  • Cocoa Touch缺少Cocoa的一些特性,但iOS SDK中也有一些功能是Cocoa目前没有的;比如iOS运动传感器

第2章 创建第一个项目

  • xcode采用LLVM(low level Virtual Machine,底层虚拟机)编译器
  • stroyboard 由一组或多组相对于的视图和控制器构成。
  • iOS Simulator -> Reset Content and Setting...清除模拟器上运行过的应用
  • 启动界面在APP加载内存的时候可以设置启动文件,View->属性检查器

第3章 实现基本交互

  • MVC:模型(应用数据)、视图(窗口控件)、控制器(模型和视图绑定的代码)
  • 输出接口 outlet
  • 现在的xcode都已经默认启动ARC,(ARC 只适用OC的对象和结构体,不能用于Core Foundation对象和C语言的内存分配)
  • stroyboard->view->Label->添加布局约束

第4章 更丰富的用户界面

  • 调整图片和视图大小一致:Command+=
  • Interface Builder中蓝色实线表示布局约束(不是引导蓝色虚线),橙色实线控件与背景视图的位置关系;
  • Interface Builder中调整视图大小是按Option显示辅助线方便调整视图大小
  • Alpha透明属性(0-1):0.0完全透明,1.0完全不透明
  • Drawing.Tint属性视图下方是否需要绘制内容,默认选中会优化当前视图的绘制
  • Clears Graphics Context 绘制视图前是否绘制黑色透明覆盖对象所有区域(默认不选)
  • Clip Subviews 视图与子视图大小不一致时边界显示覆盖控制(默认关闭)
  • Autoresize Subviews视图大小变化时自动调整子视图(默认选中)
  • Stretching矩阵视图大小重绘才拉升
  • 选中所有视图对象,Editor -> Resolve AutoLayout Issues -> Add Missing Constraints,设置约束(默认约束以边缘靠近原则编译时自动创建)
  • stroyboard中选择文本框,按Option+Command+6打开连接检查器,选择操作方法拖动到视图上方的ViewControl
  • Touch Up Inside(按钮控件)和Touch Down(背景按键)区别在于是否关心按下动作离开位置
  • 添加新增控件约束并更新Editor -> Resolve Auto Layout Issues -> Add Missing Constraints 和Update Constraints
  • 方法与接口关联:Ctrl+左键拖动(右键拖动)到代码中
  • Interface Builder中按Option拖动对象创建对象副本
  • 视图中限制位置后(Editor -> Align -> Horizontal Center in Container),还需要右键调整视图位置留出间距(背景转蓝色位置),释放后菜单选择Top Space to Top Layout Guide(垂直方向)以固定控件与视图顶间距
  • 右键拖动控件到左上角,是否鼠标,再Shift跳出菜单选择Leading Space to Container Margin(水平方向+间距) 和 Top Space to Top Layout Guide,完成添加约束
  • 按钮切片:Show Slicing按钮后,进行水平和垂直的拉升

第5章 自动旋转和自动调整大小

  • 自适应布局,尺寸分类可以实现在选择前后的不同布局

第6章 多视图应用

  • 导航栏、标签栏(工具栏)
  • 多视图情况下一般当前不显示视图延迟加载、已加载的不显示视图在内存不足情况下释放


第7章 分页栏与选取器

  • 分页视图控制器UITabBarController
  • 选取器如UIDatePicker(日期选择器)、UIPickerView(可自定义选择项)

第8章 表视图简介

  • 表视图是向用户显示数据列表的一种常用方式;
  • 表视图(UITableView)只能一列,不限制行数(每行一个UITableViewCell实例)
  • 表视图单元格在界面滚动的时候cell重用
  • 通过UITableViewDelegate定义TableView协议
  • 定制表视图单元:1、向表示图单元添加子视图;2、从nib文件中加载单元;3、从stroryboard中加载单元;
  • 视图调试器:可以对正在运行的APP拍下视图层级关系的快照(调试的时候Debug->View Debugging->Capture View Hierarchy),再用来在编辑器中检查

第9章 导航控制器和表视图

  • 先实现导航控制器和根视图控制器,再为层级结构添加更多的控制器和层;实现表视图与子视图的切换表视图与内容视图切换(详细内容的编辑)、表视图拆分多个分区、编辑模式下的删除、排序
  • 导航控制器 UITableViewController和视图控制器UITableViewController
  • 转场(seuge),一种过度,在两个试图控制器之间的相连的转场;转场也有identifier,表示控制不同控制器过度时的代码逻辑。

第10章 集合视图

  • UICollectionView用于展示集合视图,布局更加灵活,可实现多列布局
  • 自定义单元格用UICollectionViewController替换默认的UIViewController
  • 使用UICollectionView 必须实现UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout这三个协议

第11章 分割视图和浮动窗口

  • 分割视图master-detail应用程序:MasterViewControl、DetailViewControl
  • nib文件是静态对象图,应用加载时包含对象会全部加载并一直存在;而stroyboard中包含多个场景,可以一部分;
  • 浮动窗口UIPopoverController(只会自行显示并消失)
  • 避免保留连环(retain cycle)的方式其中一个定义成weak(不对对象拥有所有权)

第12章 应用设置和用户默认设置
  • 选择*.plist中的节点右键选中Show Raw Keys/Values,再进行字典字段编辑
  • NSNotificationCenter通知,注册观察者对某个事件,用于配置的更改实时生效;通知是对象之间通信的轻量级机制

第13章 数据持久化基础知识

  • 持久化机制常见方法:属性列表、对象归档、嵌入SQLite3、Core Data
  • 应用沙盒:Documents、Library、tmp
  • Core Data 是数据持久化存储的最佳方式
  • Core Data 在复杂应用中,可以显著减少设计和编写数据模型所需要的时间

第14章 文档和iCloud



第15章 Grand Central Dispatch和后台处理

  • GCD通过将高代价任务推迟执行并调至后台运行的方式来提升App的交互速度
  • GCD提供比锁与多线程更简单的并发模型,以此来避免一些由并发引起的Bug
  • UIActivityIndicatorView 提供轻型视图,会显示一个标准的旋转进度轮,start的时候可以吸附在当前视图中,stop的时候就会移除
  • 代码块(也就是闭包、lanbda);代码块外部变量需要__block 声明,才可以在代码块内部修改外部也生效
  • 后台线程不可以向前台GUI对象发送消息,需要传给主线程处理,在dispatch_async(dispatch_get_global_queue(),代码块中    dispatch_async(dispatch_get_main_queue(),^{...处理GUI对象...})。。。 )
  • dispatch_group_async(group, queue, ^{A}),线程组中并发执行的代码块
  • dispatch_group_notify(group, queue, ^{Z}),线程组中代码块(A\B\C)都执行完毕后,才执行的代码块(Z)
  • NSLog(@"%@", NSStringFromSelector(_cmd));,打印当前函数名,_cmd始终放回当前方法的选择器
  • 程序状态说明:未运行;活跃(屏幕上运行的程序);不活跃(在其他状态之间临时过的的阶段);后台(获取一定时间执行一些代码但无法访问屏幕和用户输入;除非运行需要一般5s后变成挂起);挂起(程序冻结不再执行);
  • 不要通过applicationWillTerminate保存程序运行状态,应该在applicationDidEnterBackground中;因为程序仅在后台状态(音频播放、GPS定位),并且用户或系统强制退出才调用applicationWillTerminate
  • 程序运行时收到短信通知等待触发时,程序会applicationWillResignActive,但并不applicationDidEnterBackground;如果关闭通知则程序applicationDidBecomeActive;如果回复通知则程序applicationDidBecomeActive,再applicationWillResignActive,再applicationDidEnterBackground
  • 程序退出前通过beginBackgroundTaskWithExpirationHandler申请更多的处理时间,endBackgroundTask告诉系统处理完成,可以真正退出
  • dispatch_after(dispatch_time(DISPATCH_TIME_NOW2 * NSEC_PER_SEC),

                           dispatch_get_main_queue(),

                           ^{ 延迟2s 后执行的代码});


第16章 使用CoreGraphics绘图



第17章 SpriteKit游戏框架



第18章 轻点、触摸和手势

  • 手势动作识别器UISwipeGestureRecognizer
  • 轻点动作识别器UITapGestureRecognizer
  • 捏合缩放识别器UIPinchGestureRecognizer

第19章 CoreLocation和MapKit

  • CLLocationManager、CLLocation、CLLocationDistance


第20章 陀螺仪和加速计

  • 加速计测量加速度和重力(三轴加速计),陀旋仪传感器测量设备围绕轴旋转值;
  • CMMotionManager、CMDeviceMotion(CMAccelerometerData and CMGyroData)

第21章 摄像头和照片库

  • 图片控件UIImageView
  • 视频没有控件可以通过控制器里的view实现,如MPMoviePlayerController.view
  • viewDidLoad在试图加载的时候调用,viewDidAppear在试图每次出现的时候调用,所以图片或视频选择或取消选取之后试图的更新可以在viewDidAppear里调用update

第22章 应用本地化

  • NSLocale用户语言和地区首选项
  • NSLocalizedString本地化通过关键字找到对应的配置值


其他

  • #pragma编译器指令(IDE),代码中 "#pragma mark xxxx",为了方便查找和导航代码用的,或者"/ MARK:xxx"
  • 尽量用NSInteger,不用Int,是因为编译器会自动选择合适的目录类型编译(如int64下NSInteger64位)


快捷键:
模拟器
  • shift+command+H,运行放回主界面
  • shift+command+H+H,切换到程序退出的选择页面
  • Option+触摸按键,旋转和捏合
  • Shift+Option+触摸按键,多点触摸滑动
  • Command+左(右)键,旋转设备

xcode
  • 关键字+Option -> ? ,再点击可以得到帮助列表
2016-10-05 13:33:06 dkq972958298 阅读数 1791

在iOS开发中,我们有时候可能会保存某些页面的数据,比如需要截屏之类的。在进行图片获取之后,如果图片过大,我们需要对图片进行压缩处理。实质上就是进行图片的重新绘制,重新生成一张图片。

代码如下

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
//可以压缩 或者 截屏
@interface ImageTool : NSObject

//返回单例的静态方法
+(ImageTool *)shareTool;

//返回特定尺寸的UImage  ,  image参数为原图片,size为要设定的图片大小
-(UIImage*)resizeImageToSize:(CGSize)size
                 sizeOfImage:(UIImage*)image;

//在指定的视图内进行截屏操作,返回截屏后的图片
-(UIImage *)imageWithScreenContentsInView:(UIView *)view;

@end


#import "ImageTool.h"
#import <QuartzCore/QuartzCore.h>

@implementation ImageTool

static ImageTool *_shareImageTool =nil;
//返回单例的静态方法
+(ImageTool *)shareTool
{
    //确保线程安全
    @synchronized(self){
        //确保只返回一个实例
        if (_shareImageTool == nil) {
            _shareImageTool = [[ImageTool alloc] init];
        }
    }
    return _shareImageTool;
}

-(id)init
{
    self = [super init];
    if (self) {
        
    }
    return self;
}

//在指定的视图内进行截屏操作,返回截屏后的图片
-(UIImage *)imageWithScreenContentsInView:(UIView *)view
{
    //根据屏幕大小,获取上下文
    UIGraphicsBeginImageContext([[UIScreen mainScreen] bounds].size);
    [view.layer renderInContext:UIGraphicsGetCurrentContext()];
    
    UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    return viewImage;
}

//重新生成图片的方法
-(UIImage*)resizeImageToSize:(CGSize)size
                 sizeOfImage:(UIImage*)image
{

    UIGraphicsBeginImageContext(size);
    //获取上下文内容
    CGContextRef ctx= UIGraphicsGetCurrentContext();
    CGContextTranslateCTM(ctx, 0.0, size.height);
    CGContextScaleCTM(ctx, 1.0, -1.0);
    //重绘image
    CGContextDrawImage(ctx,CGRectMake(0.0f, 0.0f, size.width, size.height), image.CGImage);
    //根据指定的size大小得到新的image
    UIImage* scaled= UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return scaled;
}

@end



2016-08-18 10:09:00 weixin_43172830 阅读数 22

1、RunLoop

  • 1)运行循环:

    • 运行循环在 iOS 开发中几乎不用,但是概念的理解却非常重要。

    • 同一个方法中的代码一般都在同一个运行循环中执行,运行循环监听 UI 界面的修改事件,待本次运行循环结束时,统一将界面的修改渲染出来。
    • 点击事件触发结束后立即结束本次运行循环。

    • 作用:

      • 保证程序不退出。
      • 负责监听所有事件,例如:手势触摸,时钟触发,网络加载数据完成等。
    • 特性:

      • 没有事件时,会休眠(省电),一旦监听到事件,会立即响应。
      • 每一个线程都有一个 runloop,但是只有主线程的 runloop 会默认启动。子线程的运行循环默认是不启动的。
  • 2)子线程运行循环:

    • 子线程的运行循环默认是不启动的。

    • 启动运行循环后,如果不停止运行循环,不会执行后续的任何代码,会形成一个死循环。

    • 一旦停止了运行循环,后续代码能够执行,执行完毕后,线程被自动销毁。

  • 3)响应者链条事件监听过程:

    RunLoop1

2、运行循环的使用

2.1 时钟调度

    /*
        - (void)addTimer:(NSTimer *)timer forMode:(NSString *)mode;
        
        NSDefaultRunLoopMode: 时钟,网络。           发生用户交互的时候,时钟会被暂停
        NSRunLoopCommonModes: 用户交互,响应级别高。   发生用户交互的时候,时钟仍然会触发,如果时钟触发方法非常耗时,
                                                   使用此方式时用户操作会造成非常严重的卡顿。
    */
  • 以 NSRunLoopCommonModes 方式创建

        // 调度时钟
        self.timer = [NSTimer timerWithTimeInterval:1.0 
                                             target:self 
                                           selector:@selector(updateTimer) 
                                           userInfo:nil 
                                            repeats:YES];
    
        // 将时钟以 NSRunLoopCommonModes 模式添加到运行循环
        [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
  • 以 NSDefaultRunLoopMode 方式创建

        // 调度时钟
        /*
            默认将时钟以 NSDefaultRunLoopMode 模式添加到运行循环
        */
        self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 
                                                      target:self 
                                                    selector:@selector(updateTimer) 
                                                    userInfo:nil 
                                                     repeats:YES];
  • 子线程运行循环

        dispatch_async(dispatch_get_global_queue(0, 0), ^{
    
            // 在子线程开启时钟,由于子线程的运行循环没有启动,所以没法监听时钟事件
            self.timer = [NSTimer timerWithTimeInterval:1.0 
                                                 target:self 
                                               selector:@selector(updateTimer) 
                                               userInfo:nil 
                                                repeats:YES];
    
            [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
    
            // 启动子线程的运行循环,这句代码就是一个死循环!如果不停止运行循环,不会执行后续的任何代码
            CFRunLoopRun();
    
            // 停止子线程运行循环之前,不会执行添加到此处的任何代码
        });
    
        // 运行循环执行操作方法
        - (void)updateTimer {
    
            static int num = 0;
    
            NSLog(@"%d %@", num++, [NSThread currentThread]);
    
            // 满足条件后,停止当前的运行循环
            if (num == 8) {
    
                // 一旦停止了运行循环,后续代码能够执行,执行完毕后,线程被自动销毁
                CFRunLoopStop(CFRunLoopGetCurrent());
            }
        }

清除缓存 iOS

阅读数 4115

iOS单例销毁

阅读数 2746

没有更多推荐了,返回首页