1、Xcode必备开发技巧和知识
工作中子控件最好用@property(nonatomic,weak) UIButton *button; 然后self.view addSubview 就实现了强引用了 学习的时候为了快速所以就先用了strong
如果用到懒加载一般用strong
@property(nonatomic,weak) UIActivityIndicatorView *loadingView; viewDidLoad(){ [self.view addSubview:loadingView]; self.loadingView = loadingView; }
-----------------
图文混排 新闻列表用UIWebView 网页来做
-----------------------
多抽方法到分类 自定义控件里 写项目会很快 1-2个星期就一个项目
github.com里有很多好用的分类 有的还有特效
-----------------------
查看api CGRectMake放法的所在位置 则左侧展示出
-----------------------
pch文件使用注意
去公司第一件事情查看公司Log写法 NJLog
(
作用
pch文件的应用常见
用来定义一些全局的宏 #define Number 10
用来导入一些全局都能用到的头文件
用来自定义log
// __OBJC__这个宏,在所有的.m和.mm文件中默认就定义了这个宏
#ifdef __OBJC__
// 如果这个全局的头文件或者宏只需要在.m或者.mm文件中使用,
// 请把该头文件或宏写到#ifdef __OBJC__ 中
// 因为 项目中所有文件都会导入这个文件包括.c文件 但是.c文件没有定义__OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#define ABC 55
#import "Constant.h"
#ifdef DEBUG 如果程序处于开发阶段 系统会自动定义DEBUG宏 , 如果程序处于发布阶段 系统会删除DEBUG宏定义
#define NJLog(...) NSLog(__VA_ARGS__) ... 代表多个参数 如:NJLog(@"%@-%@-%@-%@",a,b,c,d); NSLog(__VA_ARGS__)为固定写法 NJLog(***)自动转为了NSLog(***)了
#else
#define NJLog(...) 去公司第一件事就是看看pch文件 查看Log的替代写法 以后都使用这种方式打印Log 否则会很惨 发布阶段自动删除 NJLog(***) 变成空了
#endif
#define iOS7 ([[UIDevice currentDevice].systemVersion doubleValue] >= 7.0)
#endif
//#define Number 10
//#import "NJGlobal.h" //如果头文件里用了大量大 #if #endif 应该在这里定义 如NJGlobal.h
)
-----------------------------
xcode程序常见文件夹和文件
xcode-products文件夹做mac开发用的 iphone开发没有用
Framework下的框架 是开发中所依赖的框架 如fundation框架 xcode-6.4没有这个文件夹了
Test下文件是单元测试用的
InfoPlist.Strings做本地化语言用的
----------------
info.plist文件
info.plist应用程序的配置
修改info.plist 后需要 到模拟器上把应用程序删除 并把xcode product->clean清楚缓存一下
( info.plist也可以在图形化界面里修改 在xcode点击应用程序文件-》genral里设置
bundle display name - 应用程序名称
bundle identifier - 应用程序唯一标识 命名规则倒写域名+应用程序名称
bundle version string,short - 正式的版本号 在itunes上查看到等 app store上传应用程序 后面的版本号数字必须要比大于前一次 否则审核不通过
bundle version - 公司内部人员查看的版本
main storyboard file base name - 首次加载的storyboard名称 如:main
supported interface orientations 屏幕支持的旋转方向
)
------------
ARC项目里有非ARC文件配置
GDataXMLNode.m有release代码 所以是非ARC
xcode->项目-》build phases->设置 GDataXMLNode.m -fno-objc-arc
------------
程序第一次出错位置 代码出错位置
步骤:
1、添加breakpoint
2、运行程序 ,会停在第一次出错的位置上
3、可以分析出self.index这里出了问题了
4、如果程序还是在main中停止了 只有一个原因,就是连线问题
并将
再运行程序 在main中停了 在错误输出中可以找到 出错的连线是哪个了 scrollView
---------------------------------
iphone开发appIcon需要准备的图片
help ->Xcode overview 搜索文章 Icons for iPhone-only Apps
做iphone开发需要准备这些图片就可以了
启动图标AppIcon 说明
手机采用点dp作为基本单位 非视网膜屏宽度是320个点
视网膜屏里宽度上占据320个dp点 640px 视网膜屏是320个点
1、
spotlight是搜索出现应用程序的图片
2、
2x 40pt 对应的是80*80像素
-------
iphone启动图标 launchImage
R4对应的是retina 4寸屏 iphone5s等 高度为568dp 高度占用1136px
点击查看尺寸, 选择合适素材拖进去
R4找高度568的图片
----------
xcode6.4新建launchImage然后拖动相应图片到对应位置上
设置启动图片配置
(这个是上面内容的来源)http://www.cnblogs.com/w413133157/p/4337516.html (xcode6设置启动图片)
-----------------
下断点看程序执行顺序
---------------
垂直约束 水平约束 取消约束
界面布局设置为 4寸 硬件旋转,如果不正常 然后设置水平约束
----------------
导入其他项目中的素材
找到image.assets->右键 show in finder ->拷贝 别人项目中的image.assets文件夹下的 lol文件夹(里面包含了11233.imageset 1121212.imageset等包装好的图片)
-》粘贴到自己项目中的image.assets文件夹(lol文件夹存放在image.assets文件夹下)
-----------------
系统头文件修改后处理
xcode->preferences->locations->derived data 进入 删除 derived data换成目录里面的所有文件
----------------
写入代码块
代码块文件位置
xcode->preferences->locations->derived data 同级目录
找到userData/CodeSnippers/代码块文件
我的电脑中代码块位置 /Users/imac/Library/Developer/Xcode/UserData/代码块文件
----------------
xcode常用快捷键
http://www.cocoachina.com/ios/20141224/10752.html
-------------
NSArray NSDictionary重写的方法
Log必备文件
- (NSString *)description
{
return [NSString stringWithFormat:@"<%@: %p> {title: %@, cars: %@}", self.class, self, self.title, self.cars];
}
------
注释小技巧
#if 0
代码
#endif
------
约定
Cell 应该用contentView 不能用backgroundView
-------------
文件夹整理给别人用 Classes - Model Views Controllers Other目录
根据项目文件夹层次-》show in finder里新建相应的文件夹 把文件拖进去
xcode文件变红色了 -》直接delete -》把show in finder里的文件夹再拖回来
以后新建文件位置都会存放正确了
image.assets storyboard拖到supporting files里 (真实目录里已经是这样 不用管理)
---
代码文件夹管理
storyboard -》image.assets资源文件放到 supporting files里 , 新建MVC group目录 选中文件new group from selected files
delegate放到others里
mvc + others目录都放到classes目录里 new group from selected files
-------
自定义对象copy 方法 copyWithZone 0821-tableView cell
Student *p2 =[p copy];
工作中常用的自定义对象copy //Person.m - (id)copyWithZone:(NSZone *)zone //zone参数不用管 极少用到 内存用的 { // 1> 实例化对象,self 是对象 // self.class能够保证继承的子类同样使用copy方法 Person *p = [[self.class alloc] init]; // 2> 给属性赋值 p.name = self.name; p.age = self.age; // 3> 返回新对象 return p; } //Student.m - (id)copyWithZone:(NSZone *)zone { // 直接调用父类的copy方法 Student *s = [super copyWithZone:zone]; // 赋值,只需要给子类的属性赋值即可! s.no = self.no; // 返回 return s; }
copy简介
copy简介 copy mutableCopy操作导致类型变化:[[array mutableCopy] class] [[array copy] class] copy === 变成NSArray mutableCopy == 变成NSMutableArray 具有强制转换效果 地址变化:[array copy]地址不变 (对象自定义copyWithZone操作地址会改变 Student *p1 = [p copy];) [arrayM copy] [arrayM mutableCopy] [array mytableCopy]这3个地址都改变 只有执行了 NSMutableArray *arr2 = [arrM copy]; arr2实际上还是NSArray 因为copy转化为NSArray了 左边的NSMutableArray定义是我们一厢情愿罢了 一般也不这么做 @property (nonatomic, copy) NSMutableArray *arr === NSMutableArray *arr = [arr copy] 这样 实际上arr是 NSArray了 @property (nonatomic, copy) NSString *name; p.name = strM;//name(NSString类型) 有了copy [strM copy]操作后地址改变了 ,所以 修改strM后不影响 name的值, 如果name用了strong 就没有copy操作 (p.name和strM地址一样) 这样直接修改strM的内容 也会导致p.name跟着变化 所以不能用strong
------
strong 和 weak
strong weak - retain assign - set方法里有release操作 直接赋值基本数据类型不存在release操作 - 强引用 弱引用 - 引用计数器+1 引用计数器不变
__weak Person *p = [[Peson alloc] init];//__weak Person表示 堆区Person对象里引用计数器为0 新创建的Person对象复制给 __weak类型的变量 真实Person对象里的引用计数器为0 过了这一行p会被销毁
所以只有 Person *p = [[Person alloc] init]; __weak Person *p1 = p; p.name=@"aaa"; 这时候p不会销毁了
非arc(非自动代码内存管理)的 set方法
#import <Foundation/Foundation.h>
/*
1.set方法内存管理相关的参数
* retain : release旧值,retain新值(适用于对象类型)
* assign : 直接赋值(默认,适用于非对象类型)
* copy : release旧值,copy新值
-(NSArray *)statusFrames { if (_statusFrames == nil) { NSString *fullPath = [[NSBundle mainBundle] pathForResource:@"statuses.plist" ofType:nil]; NSArray *dictArray = [NSArray arrayWithContentsOfFile:fullPath]; NSMutableArray *models = [NSMutableArray arrayWithCapacity:dictArray.count]; for (NSDictionary *dict in dictArray) { NJWeibo *weibo = [NJWeibo weiboWithDict:dictArray]; //根据模型数据创建frame模型 NJWeiboFrame *wbF = [[NJWeiboFrame alloc] init]; wbF.weibo = weibo; [models addObject:wbF]; } self.statusFrames = [models copy]; // copy得到一个新地址 可变数组和不可变数组间通过copy才不报错 否则报错 } return nil; }
models copy]转化为了NSArray类型 如果这里不转 会报类型不兼容错误 @property (nonatomic,strong)NSArray *statusFrame;
------
block循环引用问题解决
@property (nonatomic,copy) BlockAbc option;
obj.option = ^{
这里面不能出现self obj 或者强引用obj的对象 如果要使用self 应该用一个若指针变量a指向self 然后在用a来完成操作
}
官方推荐控件使用weak 因为self.view addSubview数组已经强引用sw了
-
block里可以用self的情况
这个block可以用self
因为这个block是传递到sendAsynchronousRequest方法里作为一个参数 没有被任何变量强引用
-----
NSLog(@"%@",变量) 快捷方式
po 等同于 NSLog(@"%@",noti);
------------
未完成的代码用#warning标记一下
#warning 设置cell高度 未完成的代码 重要的代码位置 以后也方便复习浏览查看
-------
控件不显示原因 打印父控件的frame是否为 0000
如果是父控件frame是 0000
那么就要在自定义的UITableHeaderFooterView对象里实现方法 - (void)layoutSubviews方法里加载 子控件 而不能在tableview的自定义headerView里修改子空间imageView的frame CGAffineTrasformTranslate() 里
layoutSubviews在当前控件的frame修改时候会调用
-
自定义Cell 指定storyboard中- tableViewController - TableView - TableViewCell控件的类为自定义Cell
在数据源中创建自定义Cell
自定义cell必须有frame宽度高度 如果没有就会创建一个默认的frame
initWithStyle:style reuseIdentifier:resu//在有storyboard指定cell情况下 ,不要这样写了,因为storyboard已经有一个初始化cell的工作了 ,
如果要进一步对cell进行修改 可以在awakeFromNib里操作(cell子控件里补充初始化的东西 注意这里最好不要设置子控件的frame )
cell的子控件添加操作只能 [cell.contentView addSubView]
一句话 frame修改 或者子控件frame操作在layoutSubviews(布局子控件)
控件的设置位置
segue上传下数据(navigationController push),给下控制器的view子控件设置值应该在下控制器的viewDidload()里设置 尤其是在涉及到segue的时候 因为控制器的view是懒加载的
----
@property写法
// 有的人用strong 也可以
@property (nonatomic, copy)NSString *str;
@property (nonatomic, weak) id<协议> delegate;
@property (nonatomic, strong)NSMutableArray *messages;
@property (nonatomic, strong)NSArray *arrLists;
@property (nonatomic, assign)CGRect *arrLists;
@property (nonatomic, assign)XXBlock block;
@property (nonatomic, assign)int num;
@property (nonatomic, strong)UILabel *labeltest;//如果用weak 需要先实例化一个对象newLabel并添加到self.view中 再self.labeltest = newLabel;
@property (nonatomic, strong) Class me;
错误的写法@property (nonatomic,strong) UIImageView *newImageView;属性名中不能包含new
#import "HMMessageCell.h" #import "HMMessageFrameModel.h" #import "HMMessageModel.h" #import "Constant.h" #import "UIImage+ResizImage.h" @interface HMMessageCell() //时间 @property (nonatomic, weak)UILabel *time; //正文 @property (nonatomic, weak)UIButton *textView; //用户头像 @property (nonatomic, weak)UIImageView *icon; @end @implementation HMMessageCell + (instancetype)messageCellWithTableView:(UITableView *)tableview { static NSString *ID = @"messageCell"; HMMessageCell *cell = [tableview dequeueReusableCellWithIdentifier:ID]; if (cell == nil) { cell = [[self alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID]; } return cell; } - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { //1.时间 UILabel *time = [[UILabel alloc]init]; time.textAlignment = NSTextAlignmentCenter; time.font = [UIFont systemFontOfSize:13.0f]; [self.contentView addSubview:time]; self.time = time;
2.@property属性的用法
* weak(assign) : 代理\UI控件
* strong(retain) : 其他对象(除代理\UI控件\字符串以外的对象)
* copy : 字符串
* assign : 非对象类型(基本数据类型int\float\BOOL\枚举\结构体)
----------
block用来存放MBProgressHUD代码
属性为block用来保存block方法代码 self.option = 弹出提示框代码(MBProgressHUD) 用的时候直接调用
block快捷键 inlineBlock
block和函数的区别 block本质上和宏差不多 是指向代码的
运行的时候把某个代码拿来
----------
枚举类型参数上双击然后就可以去掉两边的()
----------
模拟器键盘弹不出处理
模拟器-》硬件-》
一个都不保留 或者只保留 ios uses same layout as osx
-----------
提示框
MBProgressHUD
我的微云:
-------------
MJ做的实用框架
https://github.com/CoderMJLee
-----------
左边的xxs.m文件 拖动到 辅助视图右边打开,可以方便些代码 还能看到storyboard ,很实用
-----
有的公司可能不允许用storyboard
------
IOS推出新东西跟进方式
主要方法:ios 7 UI transition guide里面说明了新的api属性用法 【官方文档 最好的】
其他了解即可:
搜索document and api 搜索 ios8 或者 9 或者10.。。
ios6到7有改变的地方
方法的改变搜索 image imageName方法的改变
----------
stackoverflow 可以找到很多问题答案 专业的it技术问答网站
------
简单东西说1到2个月完成 万万不可说很短时间
--------
查看真机沙盒的方法位置
----
真机发送请求任务 不要设置电脑为自己的代理 获取网络数据 否则电脑帮我妈发送了请求了
-------
IOS常用文件
沙盒(程序员创建的应用程序包和 程序员代码实现保存的数据 itunes同步有的数据文件夹会被保存到手机 有的不会同步保存)位置:
【由于不同电脑位置不同 所以这个可以不看 /Users/apple/Library/Application Support/iPhone Simulator/7.0/Applications (apple是用户名, 7.0是模拟器版本) 代码部署到6.1系统的手机上这里的位置就是6.1】
代码查看应用程序所在在模拟器沙盒文件的位置 /applications/32323ssuuw888应用程序A/
// // NJViewController.m // 05-plist存储数据 #import "NJViewController.h" #import "NJPerson.h" @interface NJViewController () - (IBAction)saveDataBtnClick:(id)sender; - (IBAction)readDataBtnClick:(id)sender; @end @implementation NJViewController /** * 点击保存按钮 */ - (IBAction)saveDataBtnClick:(id)sender { // youtube做法 // NSString *path = @"/Users/apple/Library/Application Support/iPhone Simulator/7.1/Applications/A6D53E11-DDF0-4392-B2D4-FE77A96888A6/Documents/abc.plist"; // 获取应用程序沙河目录 NSString *home = NSHomeDirectory(); // 不建议写/ // NSString *path = [home stringByAppendingString:@"/Documents"]; // 不建议Documents写死 // NSString *path = [home stringByAppendingPathComponent:@"Documents"]; // NSUserDomainMask 在用户目录下查找 // YES 代表用户目录的~ // NSDocumentDirectory 查找Documents文件夹 // 建议使用如下方法动态获取 NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; // 拼接文件路径 NSString *path = [doc stringByAppendingPathComponent:@"abc.plist"] ; NSLog(@"%@", path); // NSArray *arr = @[@"lnj", @"28"]; // [arr writeToFile:path atomically:YES]; // NSDictionary *dict = @{@"name": @"lnj", @"age":@"28"}; // 调用writeToFile将数据写入文件 // [dict writeToFile:path atomically:YES]; /* plist只能存储系统自带的一些常规的类, 也就是有writeToFile方法的对象才可以使用plist保存数据 字符串/字典/数据/NSNumber/NSData ... */ // 自定义的对象不能保存到plist中 NJPerson *p = [[NJPerson alloc] init]; p.name =@"lnj"; NSDictionary *dict = @{@"person": @"abc"}; [dict writeToFile:path atomically:YES]; //文件写入都这么使用 线程安全 先往临时文件里写,再变成真实的文件 防止程序中断 } /** * 点击读取按钮 */ - (IBAction)readDataBtnClick:(id)sender { NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; NSString *path = [doc stringByAppendingPathComponent:@"abc.plist"] ; // 读取数据 NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path]; NSLog(@"%@", dict); } @end
ios8开放了不同应用程序互相访问其沙盒
文件在itunes上同步(备份操作iphone ipad应用和内容的作用)的时候会被保存在itunes上
layer是应用程序压缩包 不能存东西
【 记住一点即可 数据放到Documents里就好了 但是Document目录不能放太大文件 因为会同步到itunes 苹果会对app进行测试发现很大文件网Document里面写可能会被拒绝审核通过的
Documents
Library
Caches 很多不重要的大文件存放位置 不会被同步
Preferences 【很小的用户偏好plist可以存放一下
一般我们这个不用管,系统自动放数据 系统的偏好设置iphone-setting信息会保存在这里 我们一般不保存数据在这里 ,用户的偏好数据 如打开应用程序sogou 有一个偏好设置字体颜色 下次同步数据后这个会保存 】
tmp 应用程序结束 应该清理 系统也可能会自动清理 不会被itunes同步保存
】
数据存储 xml - plist 存储常用数据类型 preference(偏好设置) 本质也是plist NSKeyedArchiver归档(NSCoding) 自定义对象的存储 SQLite3 Core Data (数据库缺点不能存储对象 那么Core Data可以存储对像 实际上本质也是SQLite)
-
NSUserdefaults 自动保存数据到 preference文件夹下 但是只能保存一个plist(一个Array 下的n个dictionary的数据)
所以一般数据不在这里保存
NSUserdefaults对象自动保存数据到Preference目录下的***.plist里preferences的应用场景如下: 登录过后 保存第一次登录选择和写入的数据
-------
-----
显示隐藏文件 桌面操作这里不介绍了
显示:defaults write com.apple.finder AppleShowAllFiles -bool true
隐藏:defaults write com.apple.finder AppleShowAllFiles -bool false
finder->强制退出-》重启finder
-----
View和控制器的创建
初始化创建的时候采用 获取xib和不获取xib的方式
控制器有自动初始化view的操作
------
单例获取常用关键字: main shared current standard default 拿到单例的方法
-------
辅助编辑模式用上下模式
xcode->view -> assistant editor -> assistant editors on bottom
-------
设计原则
方法里创建的控制器 过了这个方法就会被销毁
需要添加这个view的时候 也添加这个控制器
一个视图添加子视图 jump.view 的时候 需要同时添加jump , 防止调到jump控制器过了这个btnClick方法被销毁
-------
QQ主流框架手动拖一拖
----------
viewDidApper里打印view的内容更准确
-----------
快速修改类名称
.h文件右键-》refactor->rename
--------
navigationController上面也可以隐藏掉
控制器关系紧密用UINavigationController 不紧密用Modal
----------
在方法名、类名上 上按住 option -》点击?-》弹出api文档简要解释 或者光标放在方法上 右侧也能看到api解释
如果想跳到苹果api文档里 可以在最下面的class reference 点击一下 就可以弹出其api文档了
API文档里还有sample code
------
看开发文档学习各种框架使用
---------
autoResizing

浙公网安备 33010602011771号