工作了两年多,一直有个“坏习惯”,就是将工作中遇到的一些问题、技巧或心得记在印象笔记里面,按理来说,作为一个开发者,要拥抱开源精神,将这些美好的东西分享给大家,或许能够帮助别人解决问题或是引起少许的共鸣。
简书给我的第一印象是:风格清新,易用,同时也是一个不错的交流技术,交流心得的好平台,趁最近在找工作的空档,抽些时间将印象笔记里面的tips、轮子或技术解决方案移到这里来。
翻了一下印象笔记的笔记本,咋一看吓一跳,将近一千条笔记!!! 根据80 20 法则,怎么也有200条对一部分人是有参考意义的。这里抽取200条比较有价值的笔记分享出来,希望看完博客的看官能够有所收获。
PS:因为有些tips是在一个swift项目中收集下来的,所以下面放出的tip既有Objective-C 也有 Swift。由于有些笔记记录的是iOS 6.0时代的一些问题,因此可能存在一些错误的地方,欢迎指正。
tip 1 : 给UIImage添加毛玻璃效果
func blurImage(value:NSNumber) -> UIImage {
let context = CIContext(options:[KCIContextUseSoftwareRenderer:true])
let ciImage = CoreImage.CIImage(image:self)
let blurFilter = CIFilter(name:"CIGassianBlur")
blurFilter?.setValue(ciImage, forKey:KCIInputImageKey)
blurFilter?.setValue(value, forKey:"inputRadius")
let imageRef = context.createCGImage((blurFilter?.outputImage)!, fromRect:(ciImage?.extent)!)
let newImage = UIImage(CGImage:imageRef)
return newImage
}
value : value代表毛玻璃效果的程度
核心内容:let blurFilter = CIFilter(name:"CIGassianBlur") 使用滤镜工具
tip 2 : 图片压缩
func imageCompress(targetWidth:CGFloat) -> UIIMage {
let targetHeight = targetWidth/width*height
UIGraphicsBeginImageContext(CGSizeMake(targetWidth,targetHeight))
self.drawInRect(CGRectMake(0,0,targetWidth,targetHeight))
let newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGrapicsEndImageContext()
return newImage
}
这里是按原UIImage比例做压缩所以:let targetHeight = targetWidth/width*height
tip 3 : SVN & Git 用法总结
一:SVN
A. 项目经理:1.创建项目—CheckIn
2.设置项目人员
B.工作人员:1.CheckOut 获取项目的完整副本,此工作只需要做"一次"
2. 工作写代码....
3.阶段性工作完成后,Commit(提交) 将自己修改的文件,上传到服务器
每天下班前一定要做一次能够编译的提交!
4.定期Update项目,从服务器将最新的内容更新到本地,每天上班第一件事情一定要做的事情!
二. Git
A.项目经理:1.创建项目push
2.设置项目人员
B. 工作人员:1.Pull从服务器下拉最新的本版
2.Commit是将修改过的代码提交至本地的代码库
3.每天下班前Push自己当前的代码到服务器
4.每天上班前从服务器Pull最新的内容
三. M / A 文件更新
对于文件夹svn支持并不好,需要在工具下选定文件夹commit
对应文件选定文件commits
由于过去在公司多半时间是做独立开发,最多人的时候也是两个人做开发,所以协作工具用的少,但是不断的关注着两种代码仓库管理工具,总结了一些tip,还有待实践验证,吐槽吧......
tip 4: UINavigationController下的坐标系
iOS 9 前:
navigationBar 如果设置了背景图片,那么可视化坐标会从navgationbar下面开始
self.navigationController?.navigationBar.setBackgroundImage(UIImage(named:"nav"), forBarMetrics:UIBarMetrics.Default)
iOS 9 后 : 坐标从状态栏下面开始
tip 5 : C字符串转成NSString & NSString转成C字符串
const char *cString = "CString";
C字符串转成NSString : NSString *str = [NSString stringWithUTF8String:cString];
NSString * str = @"NSString";
NSString转成C字符串 : const char *cString = [str UTF8String];
tip 6 : OC & Swift 代码块(语法糖)
Objective-C :
UILabel *label1 = ({
UILabel *label = [UILabelnew];
[self.view addSubview:label];
label.frame=CGRectMake(100,100,100,45);
label.backgroundColor= [UIColor redColor];
label.text=@"大家好1";
label;
});
UILabel*label2 = ({
UILabel*label = [UILabel new];
[self.view addSubview:label];
label.frame=CGRectMake(100,160,100,45);
label.backgroundColor= [UIColor redColor];
label.text=@"大家好2";
label;
});
UILabel*label3 = ({
UILabel*label = [UILabel new];
label.frame=CGRectMake(100,250,100,45);
label.backgroundColor= [UIColor redColor];
label.text=@"大家好3";
label;
});
[self.viewaddSubview:label3];
({
UILabel *label = [UILabel new];
[self.view addSubview:label];
label.frame=CGRectMake(100,310,100,45);
label.backgroundColor= [UIColor redColor];
label.text=@"大家好4";
});
Swift:
letlabel1:UILabel= {
let label =UILabel()
self.view.addSubview(label)
label.frame=CGRectMake(100,100,100,45)
label.backgroundColor=UIColor.redColor()
label.text="大家好"
return label
}()
let label2:UILabel= {
let label =UILabel()
label.frame=CGRectMake(100,200,100,45)
label.backgroundColor=UIColor.redColor()
label.text="大家好"
return label
}()
self.view.addSubview(label2)
使用语法糖的好处就是拷贝代码时只需做少许的修改就可以达到目的,如上面的栗子,想要创建多个label,只要赋值粘贴,改一处,也就是对象名称就可以轻松完成!
tip 7 : 数据持久化方式归纳总结
数据缓存方式选择:
1: fmdata数据库(增删改查) --数据需要:增删改查
2: coreData --数据需要:增删改查
3:序列化(NSUserDefault) --状态、偏好设置、默认选项
4:单独.plist --列表数据,城市信息等
5:单独.json文件 --页面列表数据
6: realm框架(增删改查) --数据需要:增删改查
7: FastCoder 某“强哥”推荐,哈哈哈!
tip 8 : 清理Profiles证书文件
~/Library/MobileDevice/Provisioning Profiles
由于平时会负责多个项目的上线管理或是开发工作,因此MAC中有很多签名文件,有时候都分不清东西南北,一不做,二不休,前往这个目录下,将文件删个精光,调试的时候用到证书再update一下当前项目的证书即可
tip 9 : 拿到当前屏幕所看到的viewController
Objective-c版本:
- (UIViewController *)getAppRootViewController
{
UIViewController *appRootVC = [UIApplication sharedApplication].keyWindow.rootViewController;
UIViewController *topVC = appRootVC;
while (topVC.presentedViewController) {
topVC = topVC.presentedViewController;
}
return topVC;
Swift版本:
func getAppRootViewController() -> UIViewController? {
var topVC = UIApplication.sharedApplication().keyWindow?.rootViewController
while topVC?.presentedViewController != nil {
topVC = topVC?.presentedViewController
}
return topVC?
}
tip 10 : 制作pch文件
步骤:
1、新建iOS->Other->PCH File
2、targets->BuildSetting->Prefix Header->设置$(SRCROOT)/文件在工程中的路径
3、pch能像以前一样正常使用
如:$(SRCROOT)/FirstProject/PrefixHeader.pch
FirstProject : pch路径中的最后一个拓展名
PrefixHeader.pch: 是pch文件名
简介:/Users/ly/Desktop/FirstProject/FirstProject
tip 11 : 设置UINavigationController title
当 UIViewController作为UINavigationController的根视图控制器的时候,将这个Nav(root)赋给 tabBarController时,
这样写:
root.title = @“title”;
那么 :self.naviagtionItem.title 会显示 title
同时 :nav.tabBarItem.title 也会显示 title
tip 12 : 判断UIScrollView是横向滚动还是竖向滚动
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer*)gestureRecognizer {
if([gestureRecognizerisKindOfClass:[UIPanGestureRecognizerclass]]) {
CGPointvelocity = [(UIPanGestureRecognizer*)gestureRecognizervelocityInView:gestureRecognizer.view];
BOOLisHorizontalPanning =fabsf(velocity.x) >fabsf(velocity.y);
return isHorizontalPanning;
}
returnYES;
}
tip 13 : 监听 backBarButtonItem 返回事件
github上搜: UIViewController+BackButtonHandler 开源项目
tip 14 : 让一个view透明度失效
self.view.backgroundColor=UIColor(colorLiteralRed:255.0/255, green:255.0/255, blue:255.0/255, alpha:0.3)
let subView = UIView()
subView.tintColor=UIColor.whiteColor()//不透明了
self.view.addSubview(subView)
tip 15 : 从ipod库中读出音乐文件
// 从ipod库中读出音乐文件
MPMediaQuery *everything = [[MPMediaQuery alloc] init];
// 读取条件
MPMediaPropertyPredicate *albumNamePredicate = [MPMediaPropertyPredicate predicateWithValue:[NSNumber numberWithInt:MPMediaTypeMusic] forProperty: MPMediaItemPropertyMediaType];
[everything addFilterPredicate:albumNamePredicate];
NSLog(@"Logging items from a generic query...");
NSArray *itemsFromGenericQuery = [everything items];
for (MPMediaItem *song in itemsFromGenericQuery) {
NSString *songTitle = [song valueForProperty: MPMediaItemPropertyTitle];
NSLog (@"%@", songTitle);
}
tip 16 : 广告标示符(adId) & adfv标示符的那些事
1.如何识别一个应用安装在同一个设备上呢?
2.如何识别一个企业的应用安装在同一个设备上呢?
苹果给我们提供了advertisingIdentifier 来解决问题1;
只要是同一台设备,那么advertisingIdentifier就是一样的
但是如果在设置-隐私-广告那里关掉这个权限或是还原设备的话,就没办法了哭死去吧
苹果给我们提供了identifierForVendor 来作为一个企业的app标示符
比如: com.game.yoyo
com.game.xoxo
只要在同一台设备上,那么identifierForVendor 是一样的
如果:com.game.yoyo
com.buyer.yoyo
不管是不是同一个应用identifierForVendor 都是不一样的
上代码:
广告id:
#import
//每个设备有唯一一个,如果重置广告或设置-隐私-关闭广告就会关闭更换
NSString*adId = [[[ASIdentifierManagersharedManager]advertisingIdentifier]UUIDString];
企业id:
NSString*idfv = [[[UIDevicecurrentDevice]identifierForVendor]UUIDString];
tip 17 : 不使用JPush等的原始推送
由于简书的一些限制,不能粘贴文件,考虑选择一个方式将我自己的实践工程放出来,以后持续更新
(MAC下搭建服务器+证书制作+推送测试)
tip 18 : 设置系统音量(排版有段乱,将就一下(⊙﹏⊙)b)
#import"VolumeSetter.h"
#import
@implementationVolumeSetter
{
MPVolumeView*volumeView;
UISlider* volumeViewSlider;
}
+ (instancetype)shareInstance
{
staticVolumeSetter*vs;
staticdispatch_once_tonce;
dispatch_once(&once, ^{
vs = [[VolumeSetteralloc]init];
});
returnvs;
}
- (void)setVolume:(float)value
{
[self getSlider];
[volumeViewSlidersetValue:valueanimated:NO];// send UI control event to make the change effect right now.
[volumeViewSlidersendActionsForControlEvents:UIControlEventTouchUpInside];
}
- (float)getVolume:(volumeBlock)handel
{
_myHandel= handel;
[selfgetSlider];
returnvolumeViewSlider.value;
}
- (MPVolumeView*)getVolumeView
{
if(volumeView==nil) {
volumeView= [[MPVolumeViewalloc]init];
[[NSNotificationCenterdefaultCenter]addObserver:self
selector:@selector(volumeChanged:)
name:@"AVSystemController_SystemVolumeDidChangeNotification"
object:nil];
}
returnvolumeView;
}
- (UISlider*)getSlider
{
[selfgetVolumeView];
for(UIView*viewin[volumeViewsubviews]){
if([view.class.descriptionisEqualToString:@"MPVolumeSlider"]){
volumeViewSlider= (UISlider*)view;break;
}
}
returnvolumeViewSlider;
}
- (void)volumeChanged:(NSNotification*)notification
{
floatvolume =
[[[notificationuserInfo]
objectForKey:@"AVSystemController_AudioVolumeNotificationParameter"]
floatValue];
NSLog(@"current volume = %f", volume);
_myHandel(volume);
}
@end
tip 19 : 提高开发效率 开发工具(转)
http://www.cocoachina.com/ios/20151110/14102.html
tip 20 : XMPP 开发与服务器搭建
待补充
tip 21 : 设置UINavigationItem 返回按钮 和 back title
1. push 之前
// back title
self.navigationItem.backBarButtonItem=UIBarButtonItem(title:"返回", style:UIBarButtonItemStyle.Plain, target:nil, action:nil)
// 特别注意:在push之前设置
self.navigationController?.pushViewController(vc, animated:true)
2.设置颜色
self.navigationController?.navigationBar.tintColor=UIColor.blackColor()
总结:
self.navigationItem.backBarButtonItem=UIBarButtonItem(title:"返回", style:UIBarButtonItemStyle.Plain, target:nil, action:nil)
self.navigationController?.navigationBar.tintColor=UIColor.blackColor()
self.navigationController?.pushViewController(vc, animated:true)
tip 22 : 语法风格
Swift : https://github.com/raywenderlich/swift-style-guide#use-of-self
OC : https://github.com/raywenderlich/objective-c-style-guide
tip 23 : 谓词
Person类:
@interfacePerson :NSObject
@property(nonatomic) NSUIntager age;
@property(nonatomic,copy)NSString*name;
@end
#import"Person.h"
@implementationPerson
- (NSString*)description
{
return[NSStringstringWithFormat:@"age=%d,name=%@",self.age,self.name];
}
@end
ViewController.m类:
Person*p1 = [[Personalloc]init];
p1.age=15;
p1.name=@"张三";
Person*p2 = [[Personalloc]init];
p2.age=25;
p2.name=@"小米";
Person*p3 = [[Personalloc]init];
p3.age=15;
p3.name=@"李四";
NSArray*arr =@[p1,p2,p3];
//谓词
NSPredicate*pre = [NSPredicatepredicateWithFormat:@"%K==%d || %K==%@ || %K=%@",@"age",15,@"name",@"张三",@"name",@"李四"];
arr = [arrfilteredArrayUsingPredicate:pre];
NSLog(@"%@",arr);
输出:
2015-12-08 11:24:05.862 Predicate[12080:634959] (
"age=15,name=\U5f20\U4e09",
"age=15,name=\U674e\U56db"
)
用于做查询操作非常棒,避免写一大堆的if else操作
tip 24 : Xcode 插件
VVDocumenter 是一个比较好用的注释控件
Alcatraz(插件管理器)http://www.tuicool.com/articles/v2eIVb
https://github.com/supermarin/Alcatraz
Xcode 6.4找不到packageManager :http://blog.csdn.net/yimu520csdn/article/details/47040041
tip 25 : 微信登录,分享等 不执行代理方法
方法一:
- (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url
{
return [WXApihandle OpenURL:urldelegate:self];
}
方法二:
- (BOOL)application:(UIApplication*)application openURL:(NSURL*)url sourceApplication:(NSString*)sourceApplication annotation:(id)annotation
{
return[WXApihandle OpenURL:url delegate:self];
}
今天做微信登陆功能,随手写一个demo,没有设置bundle id , display name,结果就不走 方法一,方法二
导致下面两个代理方法不走
- (void) onReq:(BaseReq*)req{
NSLog(@"xxxxxxxx");
}
- (void) onResp:(BaseResp*)resp{
NSLog(@"fffffffff");
}
解决方法:设置Bundle identifier 以及 Bundledisplayname ,注意要与注册获取appid secret key 时所填的保持一致.
当然其他设置也要保证设置上,比如 URL sechme , iOS9 注意适配 ATS,添加白名单
tip 26 : iOS7.0后隐藏状态栏(UIStatusBar)
现象:
升级到iOS7后,UIStatusBar的出现导致现有UI界面乱掉了。
原因:
由于写死了某些控件的绝对位置,原先隐藏UIStatusBar的代码没有在iOS7中起作用
解决方法:
iOS7以下版本隐藏UIStatusBar的方法:
- (BOOL)application:(UIApplication*)applicationdidFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
[application setStatusBarHidden:YES];
returnYES;
}
升级到iOS7后的方法:
在基类中重载UIViewController.h中的这个方法
- (BOOL)prefersStatusBarHidden NS_AVAILABLE_IOS(7_0);// Defaults to NO
- (BOOL)prefersStatusBarHidden
{
return YES;
// iOS7后以下方法已经不起作用: [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationFade];
}
tip 27 : UIColor 转 RGB
UIColor*color = [UIColorcolorWithRed:0.0green:0.0blue:1.0alpha:1.0];
constCGFloat*components =CGColorGetComponents(color.CGColor);
NSLog(@"Red: %f", components[0]);
NSLog(@"Green: %f", components[1]);
NSLog(@"Blue: %f", components[2]);
tip 28 : 抠图 & 合成图片 (转)
iOS开发-简单图片背景替换(实现抠图效果)
http://www.tuicool.com/articles/VZN3yiZ
tip 29 : Mac 生成UUID 命令: uuidgen
在命令行工具输入 $ uuidgen : 8-4-4-4-12
tip 30 : 23种设计模式
https://github.com/huang303513/Design-Pattern-For-iOS
tip 31 : 发布APP要求
发布APP要求,不能使用Beta版本的Xcode
如果一个开发团队里面有多个小伙伴,不要为了尝新将所有的Mac OX 或是Xcode都升级到Beta版本,应该由一个小伙伴进行测试感受新版本是否稳定,是否有坑,否定后果很严重,说多都是泪,您想想:重新装系统,重新下载Xcode是一件多么苦逼的事情。。。
tip 32 : UIScrollView 判断是向左滚动还是向右滚动
这是抄自项目里面的一段代码,如果您要用到判断UIScrollView向左还是向右的滚动逻辑,请先定义相关状态的全局变量
-(void)scrollViewWillBeginDragging:(UIScrollView*)scrollView
{
startContentOffsetX= scrollView.contentOffset.x;
}\
- (void)scrollViewWillEndDragging:(UIScrollView*)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inoutCGPoint*)targetContentOffset{//将要停止前的坐标
willEndContentOffsetX= scrollView.contentOffset.x;
}
- (void)scrollViewDidEndDecelerating:(UIScrollView*)scrollView{
endContentOffsetX= scrollView.contentOffset.x;
if(endContentOffsetX < willEndContentOffsetX && willEndContentOffsetX < startContentOffsetX) {
NSLog(@"画面从右往左移动,前一页");
}else if(endContentOffsetX > willEndContentOffsetX&&
willEndContentOffsetX > startContentOffsetX) {
NSLog(@"画面从左往右移动,后一页");
}
}
tip 33 : 判断是否插入SiM卡
引入:CoreTelephony.framework
extern NSString*constkCTSMSMessageReceivedNotification;
extern NSString*constkCTSMSMessageReplaceReceivedNotification;
extern NSString*constkCTSIMSupportSIMStatusNotInserted;
extern NSString*constkCTSIMSupportSIMStatusReady;
id CTTelephonyCenterGetDefault(void);
void CTTelephonyCenterAddObserver(id,id,CFNotificationCallback,NSString*,void*,int);
void CTTelephonyCenterRemoveObserver(id,id,NSString*,void*);
int CTSMSMessageGetUnreadCount(void);
int CTSMSMessageGetRecordIdentifier(void* msg);
NSString* CTSIMSupportGetSIMStatus();
NSString* CTSIMSupportCopyMobileSubscriberIdentity();
id CTSMSMessageCreate(void* unknow/*always 0*/,NSString* number,NSString* text);
void* CTSMSMessageCreateReply(void* unknow/*always 0*/,void* forwardTo,NSString* text);
void* CTSMSMessageSend(idserver,idmsg);
NSString*CTSMSMessageCopyAddress(void*,void*);
NSString*CTSMSMessageCopyText(void*,void*);
NSLog(@"BOOL:%d", [CTSIMSupportGetSIMStatus()isEqualToString:kCTSIMSupportSIMStatusNotInserted] );
tip 34 : 获取链接的Wifi
#import <SystemConfiguration/CaptiveNetwork.h>
- (id)fetchSSIDInfo {
NSArray*ifs = (__bridge_transfer id)CNCopySupportedInterfaces();
NSLog(@"Supported interfaces: %@", ifs);
id info =nil;
for (NSString*ifnam in ifs) {
info = (__bridge_transfer id)CNCopyCurrentNetworkInfo((__bridge CFStringRef)ifnam);
NSLog(@"%@ => %@", ifnam, info);
if(info && [info count]) {break; }
}
return info;
}
tip 35 : 计算文字宽度、高度
- (CGSize)currentSize{
CGFloatversion = [[UIDevice currentDevice].systemVersionfloatValue];
//计算size 7之后有新的方法
CGSize size;
if(version>=7.0) {
//得到一个设置字体属性的字典
NSDictionary*dic = [NSDictionary dictionaryWithObjectsAndKeys: [UIFontsystemFontOfSize:15],NSFontAttributeName,nil];
//optinos前两个参数是匹配换行方式去计算,最后一个参数是匹配字体去计算
//attributes传入使用的字体
//boundingRectWithSize计算的范围
//_tweetBody是string
size = [_tweetBody boundingRectWithSize:CGSizeMake(215,999)options:NSStringDrawingTruncatesLastVisibleLine|NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading attributes:diccontext:nil].size;
}else{
//ios7以前
//根据字号和限定范围还有换行方式计算字符串的size
//label中的font和linebreak要与此一致
//CGSizeMake(215,999)横向最大计算到215纵向max 999
size = [_tweetBodysizeWithFont:[UIFont systemFontOfSize:15]constrainedToSize:CGSizeMake(215,999) lineBreakMode:NSLineBreakByCharWrapping];
}
return size;
}
tip 36 : TableView UITableViewStylePlain状态去掉省略多余的cell
_tableView= [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
_tableView.delegate=self;
_tableView.dataSource=self;
_tableView.tableFooterView= [UIView new]; // 关键的一行代码
tip 37 : block 类型声明为strong 还是 copy ?
block声明为strong 和copy什么区别
block变量申明为strong或者copy 在ARC 的情况下 是等效的
但苹果推荐的最佳实践是 使用copy作为block的权限控制符
因为 copy能让开发者更明确地知道 block内存操作的隐式行为
及copy 到heap上
ARC下面 strong修饰的block 会自动进行这一过程
MRC下面 使用copy是必须的
tip 38 : 坐标转换
如果我的tableView的每个cell都有输入框,那我怎么样在输入的时候将对应的输入框移到合适的位置?
每个cell可以拿到在当前table的位置然后转换到屏幕上
然后自己算应该偏移多少
self是一个view 一个是把一个坐标从自己的换到其他的View上
一个是把其他的坐标换到自己上 如果self你当做tableView,然后后面的uiview你用vc.view
就能相互转了
tip 39 : 跳转至指定QQ号码
判断是否安装了QQ:
if([[UIApplication shareApplication] canOpenURL:[NSURL:URLWithString:@“mqq://“]]){
NSLog(@“had installed");
} else {
NSLog(@“no installed");
}
UIWebView*webView = [[UIWebView alloc] initWithFrame:CGRectZero];
NSURL*url = [NSURLURLWithString:@"mqq://im/chat?chat_type=wpa&uin=501863587&version=1&src_type=web"];
NSURLRequest*request = [NSURLRequest requestWithURL:url];
webView.delegate=self;
[webView loadRequest:request];
[self.view addSubview:webView];
tip 40 : 企业版app 与 appStore版app之间的问题
问题一 : 一台手机能否装两个名字一样的应用呢.
回答 : 能否装两个一样的应用不是取决于应用的名字,而是取决于boundid,appId(这个本人还没考究。。。)是否一致。
但是苹果应用商店是不允许有两个名字一样的应用程序的,那我们干嘛要纠结于名字一样的问题呢?
因为如果公司有一个企业账号和一个发布账号,企业账号希望发布一个到官网供用户下载,而发布账号希望发布到AppStore,而且名字一样。
结论是:两个应用同名行不行?行,只要你的企业账号发布的应用的boundid跟AppStore上的应用的app的boundid不一致,名字可以一致。
而且苹果不会管你的企业账号发布的应用程序,你爱怎么玩就怎么玩,如果你不希望一台手机装两个名字一样的应用,那么开发者 只要将两个应用的boundid设置成一样就可以了。
注意:AppStore上不能有同名的应用程序,这个是受商标保护法保护的。但是企业账号就可以任意起名字跟设置boundid。但是嘛,你懂的。。。
tip 41 : 打印 NSHomeDirectory为空
情况:打印获取 NSHomeDirectory为空,打印有值,获取到为nil。。
如果版本是release,就会出现上面的情况
解决的办法 : 设置成 debug
安全的做法是:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : NSTemporaryDirectory();
tip 42 : app跳转到safari
NSURL* url = [NSURL URLWithString:urlStr];
[[UIApplication sharedApplication] openURL:url];
tip 43 : 弹出键盘 & 收键盘
//监听键盘
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyBoardShow:)name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyBoardHide:)name:UIKeyboardWillHideNotification object:nil];
#pragma mark弹出键盘
-(void)keyBoardShow:(NSNotification*)notification
{
//notification.userInfo获得用户的所有信息,userInfo是一个字典,根据key值 为UIKeyboardFrameEndUserInfoKey拿到键盘的frame的“字符串”,将这个字符串转成Rect
int y = [[notification.userInfoobjectForKey:UIKeyboardFrameBeginUserInfoKey]CGRectValue].size.height;
}
#pragma mark收键盘
-(void)keyBoardHide:(NSNotification*)notification
{
}
最强的收键盘方法 :
[[UIApplicationsharedApplication]sendAction:@selector(resignFirstResponder)to:nilfrom:nilforEvent:nil];
其他的键盘监听 :
[[NSNotificationCenterdefaultCenter]addObserver:selfselector:@selector(keyboardWillChangeFrame:)name:UIKeyboardDidChangeFrameNotificationobject:nil];
tip 44 : 审核加急处理
链接:https://developer.apple.com/appstore/contact/appreviewteam/index.html
备注:到上面的连接填写相关桂东,申请加急的理由:上线的App中有Bug
tip 45 : iTunesConnect 更新版本接受协议步骤
tip 46 : No architectures to compile for (ONLY_ACTIVE_ARCH=YES, active arch=x86_64, VALID_ARCHS=i386).
解决的办法是 :
步骤1 :
步骤2 :
tip 47 : Version 号 跟Build 号的区别
version 是给用户看的,比如1.0 2.0
Build 是给开发者还有就是苹果 iTunesconnect看的
具体情景:
今天发布一个版本叫 2.0 所以 version 2.0
于是我要archive -> validate -> submit
发布完成了!
正当我们其乐融融的的准备庆祝的时候,屌丝的产品进来大吼一声,肃静,吵什么吵,我看那个搜附近的人页面太烂了!!!!
一万个草泥马在天上飞啊。。。
没事,蛋定,蛋定,改改改。。。
改完之后,发现validate不成功。提示:已经有一个2.0的版本了,怎么破????产品经理坚持要用version 2.0这个数字,但是如果不改成version2.1之类的好像一直都传不上去啊!!!灵光一闪,Build 号是干嘛的?经过一般查证,Build是给我们开发者和itunesconnect看的,改一下Build不就行了吗,改改改,重新validate发现可行,欧耶,submit , 重新选择版本,搞定!!!继续庆祝
tip 48 : Xcode 6中对于图片的要求规格:
1、AppIcon
(1)spotlight iOS 5-6 29*29
setting iOS 5-8 29*29 (1*2*3 三种尺寸)
(2)spotlight iOS 7-8 40*40 (2*3 两种尺寸)
(3)iPhone App iOS 5-6 57*57 (1*2两种尺寸)
(4)iPhone App iOS 7-8 60*60 (2*3两种尺寸)
2、启动图片
Default.png(320*480)
Default@2x.png(640*960)
Default-568h@2x.png(640*1136)
Default-667h@2x.png(750*1334) 4.7寸
Default-736h@3x.png(1242*2208)5.5寸
tip 49 : 清除签名文件 删除签名文件 清理Profile文件
Xcode - Preferences - Account - View Details,这个时候左下角有个刷新图标,点击一下就可以了
tip 50 : 应用内跳转到系统设置页面 (转)
http://code4app.com/ios/DBPrivacyHelper/548e7550933bf031268b4d82
tip 51 : 使用lipo命令合并对应版本 静态库文件
备注:以百度地图SDK为栗子
真机版本的文件路径: /Users/han-zi/Desktop/Release-iphoneos/libbaidumapapi.a
模拟器版本的文件路径:/Users/han-zi/Desktop/Release-iphonesimulator/libbaidumapapi.a
输出文件路径: /Users/han-zi/Desktop/a/libbaidumapapi.a
tip 52 : 应用在AppStore的地址
webpageUrl=@"http://itunes.apple.com/us/app/id+你的应用id";
tip 53 : 颜色值转RGB
- (void)setBgRGB:(long)rub{
red = ((float)((rgb & 0xFF0000) >> 16))/255.0;
green = ((float)((rgb & 0xFF00) >> 8))/255.0;
blue = ((float)(rgb & 0xFF))/255.0;
}
tip 54 : App 上线简介
心得体会:
1.准备一个APP ID(这个可以永远用)
2.创建证书
a.创建证书的过程要上传机器标示符(钥匙串——>证书助理——>从证书颁发机构请求证书))
b.要绑定APP ID
c.填写bundleID
d.下载证书
3.生成签名文件——>绑定Bundle ID ——>生成签名文件——>下载签名文件
tip 55 : UIImage加载方式怎么选?
方式一: imageName:有缓存的方式,如果一张图片会被重复用到,那么请用这种方式
方式二:contentOfFile:无缓存的方式,加载大的图片文件,特别注意,jpg图片只能以这种方式加载
tip 56 : ARC兼容MRC,MRC兼容ARC 设置关键字
ARC兼容MRC : -fno-objc-arc
MRC兼容ARC: -fobjc-arc
tip 57 : 消息推送机制理解
1.应用程序第一次起来的时候询问是否允许消息推送,允许的时候才去注册,
向苹果APNS服务器注册是哪个{应用程序,设备号}
2.注册成功苹果APNS服务器返回一个DeviceToken,程序员要保存这个{DeviceToken}
3.注册失败 。。。。
4.注册成功,将DeviceToken发给服务器{可以是自己的服务器,可以是极光服务器},服务器保存这一大堆的DeviceToken
5.服务器要推送消息{可以是极光服务器}将这个消息发给苹果APNS服务器,APNS服务器根据{一大堆的DevicToken}向应用程序推送消息
tip 58 : FMDB 事务操作步骤
@try{
启动事务,执行数据库操作
[_dataBase beginTransaction];//手动开启一个事务
}@Catch{
出现问题,数据库回滚
[_dataBase rollback];//回滚,回到最初的状态
}@finally{
数据库提交操作
[_dataBase commit];//提交事务,让批量操作生效
}
备注:FMDB 使用进阶包括两个内容,一个是事务,一个是线程安全,详细内容请看FMDB官方文档。
事务解决的问题: 如果要对数据库进行 多条数据的写操作,应开启事务,而不要只使用for循环直接写入,否则会比较耗时
线程安全解决的问题: 如果对同一资源进行操作,FMDB不是线程安全的,使用FMDataBaseQueue这个类可以做到线程安全。
tip 59 : UITableView重用机制的理解
UITableView自身有一套重用的机制,根据UITaleVIew 的frame的大小和cell.frame大小来计算个数,实际会创建多一个cell,创建的这些cell都放在一个数组(队列的数据结构)里面,视图出现时根据计算的结果将cell拿出来放在UITableView上面,剩下的那个cell则作为缓冲cell,比如向上拖动的时候,cell[0]会放回数组最下面,将那个上次没有使用的cell拿出来,放在TableView下面。利用这种机制来达到重用的目的。
对于拖到到看不见的位置的cell,我们可以对他清除缓存(缓存就是cell.contentView上面的子view),那怎么清除呢?方法很简单
-(UITableViewCell *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(cell ! == nil)
{
NSArray *arr =[ [NSArray alloc] initWithArray :cell.contentView.subviews];
for (UIView *subView in arr){
[subView removeFromSuperView];
}
}
tip 60 : UITableView Cell 清除缓存 说白了就是将将要出现的cell的contentView上面的子视图清除掉或销毁
tableView表格中的cell有重用机制,这是一个很好的东西,可以避免开辟很多的空间内存。但是有时候我们不想让它重用cell,,可以用以下的代码解决。
将这个代码放在:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
// 这个函数中执行就好了。
//清楚cell的缓存
NSArray *subviews = [[NSArray alloc] initWithArray:cell.contentView.subviews];
for(UIView *subview in subviews) {
[subview removeFromSuperview];
}
tip 61 : 改变tabBarItem字体颜色
self.tabBar.tintColor= [UIColor colorWithHexString:BLUE_GREEN_COLOR];
UITabBarController*tabBarController = (UITabBarController*)self;
UITabBar*tabBar = tabBarController.tabBar;
UITabBarItem*trainEnquiryItem = [tabBar.itemsobjectAtIndex:0];
[trainEnquiryItem setTitle:@"查询"];
[trainEnquiryItemsetImage:[UIImageimageNamed:@"tet"]];
[trainEnquiryItemsetSelectedImage:[UIImageimageNamed:@"tet_hover"]];
改变UITabBarItem 字体颜色
[[UITabBarItem appearance] setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[UIColor whiteColor],UITextAttributeTextColor,nil] forState:UIControlStateNormal];
[[UITabBarItem appearance]setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[UIColor colorWithHexString:"#00C8D3"],UITextAttributeTextColor,nil] forState:UIControlStateSelected];
tip 62 : UITextFiled 设置PlaceHolder字体颜色
#pragma mark设置Placeholder颜色
UIColor*color = [UIColorwhiteColor];
_userNameTextField.attributedPlaceholder= [[NSAttributedStringalloc]initWithString:@"用户名/邮箱"attributes:@{NSForegroundColorAttributeName: color}];
[tempUserNameImageViewaddSubview:_userNameTextField];
tip 63 : 应用主题设置心得以及思路
THEME是主题名称
同理,所有涉及到界面的地方都要监听THEME通知,
IOS有关主题的问题 ThemeManager 类
1.创建路径:初始化时先从指定的plist文件中读取主题文件
2.根据路径初始化有关主题的数组
3.如果这个数组为空,初始化为0个对象
4.接口 :
-(BOOL)downLoad:(NSDictionary *)dic Block:(void (^) (BOOL))a
{
//1.保存block
//2.从字典中获得主题名称
//3.数组中保存这个主题文件: 根据名字判断主题是否已经存在
[self.dataArray containsObject:self.tempTheme];
//4.1存在:NSUserDefault保存——>通知中心发送通知post——>结束返回
//4.2 根据url发起网络请求——>
进行下载——>
下载完成保存文件——>
}
-(void)saveData:(NSData *)data
{
保存到指定文件——>
解压缩文件——>
用NSUserDefault记录主题名,启动的时候方便读取——>
//4.3主题持久化工作
将主题名字保存到数组中,将整个数组写到初始化时的plist文件目录中 ,(里面包含所有的主题名称) writeToFile
//4.4保存完发送主题广播 post
//4.5发送广播,调用回调函数
//4.6在MainTabBarController里面配置界面,相当于设置主题,不同主题,里面的图片的名字是不一样的
}
在某个类中使用新的主题文件 比如:MainViewController:
-(void)dealloc{
[ [NSNotificationCenter defaultCenter] removeObserver:self name:THEME object :nil];
}
-(void)viewDidLoad
{
//顺序不可以颠倒
[self createTabBarItem];
//接收通知后一定要在第一次读取默认主题创建好之后再接收 createTabBarItem是布局界面的方法
[ [NSNotification defaultCenter] addObserver:self selector:@selector(createTabBarItem) name:THEME object:nil];
}
-(void)createTabBarItem
{
//设置界面主题图片
}
tip 64 : 设置UITabBarItem文字属性
//设置文字颜色
if(iOS7) {
[[UITabBarItem appearance]setTitleTextAttributes:@{NSForegroundColorAttributeName: [UIColorwhiteColor]}forState:UIControlStateSelected];
}else{
[[UITabBarItem appearance]setTitleTextAttributes:@{UITextAttributeTextColor: [UIColorwhiteColor]}forState:UIControlStateSelected];
}
tip 65 : 设置UITabBarItem背景图片
if(iOS7) {
item = [iteminitWithTitle:title[i]
image:[unSelectImageimageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]
selectedImage:[selectImageimageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]];
}else{
itemsetFinishedSelectedImage:selectImagewithFinishedUnselectedImage:unSelectImage];
item.title= title[i];
}
tip 66 : 一个View旋转一定角度
//M_PI == 3.14 == 180
[btn setTransform:CGAffineTransformMakeRotation(M_PI/7.2)];//25
tip 67 : 一些crash崩溃原因
1、对象里面没有某个方法
2、自己建的类没有NSCopying协议,就去copy
3、对某类的对象进行归档接档,没有实现NSCoding协议
4、下标越界
5、导航视图控制器出栈时,某个vc不在
6、数据为空,没有初始化
tip 68 : id类型不能用点语法
tip 69 : 设置睡眠 & 产生真正的随机数
sleep(1.f); // 睡眠一秒
arc4random()%10; // 10以内的随机数
tip 70 : 参数要遵循某种协议的写法
void play(id ins) // look at here
{
if ([ins respondsToSelector:@selector(playMusic)]) {
[ins playMusic];
}
}
tip 71 : NSString的一些特殊情况
//__autoreleasing 对象设置为这样,要等到离自己最近的释放池销毁时才release
//__unsafe__unretained不安全不释放,为了兼容过去而存在,跟__weak很像,但是这个对象被销毁后还在,不像__weak那样设置为nil
//__weak 一创建完,要是没有引用,马上释放,将对象置nil
//
__weak NSMutableString *str = [NSMutableString stringWithFormat:@"%@",@"xiaobai"];
//__weak 的话但是是alloc的对象,要交给autorelease管理
//arc下,不要release 和 autorelease因为
tip 72 : 判断类,成员,调用方法
[obj isMemberOfClass:[runTime class]] //判断是不是一个一个类的成员
[obj isKindOfClass:[NSObject class]] //是不是从属一个类,包括父类
[obj conformsToProtocol:@protocol(NSCoding)]//是不是支持这一个协议
[obj performSelector:@selector(showA:) withObject:[NSNumber numberWithInt:8]]//给方法发送消息
tip 73 : 文件操作注意事项
//NSFileHandle * fh = [NSFileHandle fileHandleForReadingAtPath:@"/Users/qianfeng/Desktop/C考试准备"];
//[fh seekToFileOffset:2];//定位到某处开始执行操作,显示的seek会更新文件指针
//NSData * data = [fh availableData];
//NSData *data = [fh readDataOfLength:2];
写文件的注意事项
voidtestArchiver()//“支持nscopy的可以写到文件”
{
NSString* str =@"123445788";
NSArray* array = [[NSArray alloc]initWithObjects:@"nihao",nil];
[strwriteToFile:@"/Users/qianfeng/Desktop/笔记本使用注意事项2.text"atomically:YES encoding:NSUTF8StringEncodingerror:nil];
[arraywriteToFile:@"djhfdj"atomically:YES];//读写保护
}
voidtest3()//NSCode是能将OC类型写到文件的
{
Myfiler* mf = [[Myfileralloc]init];
NSArray* array = [NSArray arrayWithObject:mf];
[arraywriteToFile:@"djhfdjf"atomically:YES];//失败,因为普通类Myfiler不支持nscopy协议
}
由于篇幅关系,未完待续!