昨天张梦格App的第二版已经提交上线审核。从第一天接手项目开始到第一次、第二次被苹果打回,再到第一版、第二版上线,我经历了一个完整的App从开发到上线的全过程。我想应该对这个项目做一些总结,把自己在这个项目中的收获记录下来。帮助加深记忆,巩固和提高技术
一、代码管理工具----分布式版本控制系统github,在上边新建一个项目的代码仓库,把代码同步到git服务器上。下边介绍一个常用的git终端命令:
git clone "SSH网址"从github上克隆代码到本地、
git branch 列出已有的分支、
git checkout "branchname" 切换分支名称、
git add . 添加新文件或者更改新文件、
git status 查看更新状态、
git rm "文件名" 删除github上文件、
git commit -m "name"提交更改文件到本地并且添加一个名字、
git pull /git pull origin "branchname"从服务器上拉取信息、
git push origin "branchname"提交到服务器上、
git merge 合并版本、
git log查看提交修改目录。
gitk 打开github自带图形用户界面
mate "Zhangmengge.xcodeproj" 用textmate打开工程文件
二、iphone工程命名规范:
进入工程后有四个文件夹:
第一个Resources存放的是第一次美工给的图片,包含测试图和坐标图并不是最终要添加到工程里的文件。
第二个是工程名字的文件夹。
第三个Frameworks里存放了工程所有用到的框架。
第四个是这个工程的app文件。
在工程名的文件夹里包含有5个文件夹:
第一个config是一个全局的配置文件,里边主要放所有用到的宏定义。
第二个App文件夹里放的是所有的代码文件。
第三个libs文件夹里放所有用到的第三方框架。
第四个Resources里边存放的是工程中所有用到的图片素材。
第五个supporting files是一个支持文件,里边主要是自动生成文件,例如plist文件、main函数、pch文件,在pch文件里写的主要是一些被很多页面都要引用的框架名称,写在这里边就会自动引用到所有页面。
三、 自定义Button形状的第三方框架OBShapedButton:
图片素材的其它区域要给成透明的,然后用OBShapedButton初始化创建一个对象,后边用法跟创建系统Button一样:
OBShapedButton * sharebtn = [OBShapedButton buttonWithType:UIButtonTypeCustom]; sharebtn.frame = CGRectMake(10, 40, 300, 436); [sharebtn setImage:[UIImage imageNamed:@"xiepinglun_backgound_cut.png"] forState:UIControlStateNormal]; [sharebtn addTarget:self action:@selector(onTop) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:sharebtn];
四、textview、textfield回收键盘方法:
都需要把delegate设成自己:
-(BOOL)textFieldShouldReturn:(UITextField *)textField { [textField resignFirstResponder]; return YES; } -(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text { if ([text isEqualToString:@"\n"]) { [textView resignFirstResponder]; return NO; } return YES; }
五、字符串替换、数组反向排序:
//字符串替换 self.finalStr = [self.tempStr stringByReplacingOccurrencesOfString:@"</p>" withString:@" "]; //将数组元素反向排列 [self.articleList reverseObjectEnumerator];
六、修改编译文件(Build)位置:
编写程序时经常会出现一些莫名其妙的错误,而且怎么找都找不到错误,这个时候就该考虑一下是不是build的问题,需要clean build一下。在xcode里Preferences里的Locations把Derived Data的Default改成Relative,然后把后边括号里改成build,这样每次编译会在你的工程目录里多出一个build文件夹,在出现奇怪错误时可以build目录清理一下。
七、DLog:
编写程序时经常需要用NSLog输出一些数据,当整个程序写完时可能已经写了无数个NSLog,不可能一个一个删了,而且日后如果修改还需要在写非常麻烦。解决办法在.pch里写这样一段宏命令
//把NSLog换成DLog,以后就不用一个一个删除 #ifdef DEBUG # define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); #else # define DLog(...) #endif // ALog always displays output regardless of the DEBUG setting #define ALog(fmt, ...) NSLog((@"%s [line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
然后在程序中需要用NSLog的地方全部换成DLog。编写程序时把Edit SchemeL里Build Configuration选项改成Debug(默认就是Debug),程序会正常输出打印。当上线发布时把Debug改成Release,所以DLog就不会打印输出了。
八、如何判断设备是iphone5:
在.pch里添加一段宏命令
//判断设备是不是iphone5 #define iPhone5 ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(640, 1136), [[UIScreen mainScreen] currentMode].size) : NO)
在程序中只需判断:
if (iPhone5) { // Initialization code ... }
九、去掉cell选中时的蓝色背景:
在cellForRowAtIndexPath里加上一句话:
static NSString *CellIdentifier = @"Cell"; MyCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; // Configure the cell... if (cell == nil) { cell = [[[MyCustomCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]autorelease]; } //设置选中后cell的背景颜色,有黑色,灰色,蓝色,和不显示颜色四种 cell.selectionStyle = UITableViewCellAccessoryNone;
十、如何判断程序第一次进入:
在AppDelegate里开始位置写
//判断程序是否第一次进入 if (![[NSUserDefaults standardUserDefaults]boolForKey:@"everLaunched"]) { [[NSUserDefaults standardUserDefaults]setBool:YES forKey:@"everLaunched"]; [[NSUserDefaults standardUserDefaults]setBool:YES forKey:@"firstLaunch"]; }else{ [[NSUserDefaults standardUserDefaults]setBool:NO forKey:@"firstLaunch"]; } // Save changes to disk [[NSUserDefaults standardUserDefaults] synchronize];
在需要对第一次进行操作时写:
-(void)firstLaunch { if ([[NSUserDefaults standardUserDefaults]boolForKey:@"firstLaunch"]) { // Initialization code }else { // Initialization code } }
十一、IOS的沙盒机制:
IOS为每个应用程序都创建了一个文件系统,每个应用程序只能读取这个文件系统中的文件,不能访问其他程序的文件系统。此区域就被称为沙盒,所有的非代码文件都保存在这里。例如图像、声音、属性列表、本地文件等。有两点需要注意:
1.每个应用程序都有属于自己的储存空间。
2.每个应用程序只能访问自己的空间,不能访问其他程序的储存空间。
每台MAC电脑的用户名文件夹下都有一个默认隐藏的文件夹,叫资源库:
1.显示资源库的终端命令:chflags nohidden ~/Library/
2.隐藏资源库的终端命令:chflags hidden ~/Library/
显示Mac隐藏文件的命令:defaults write com.apple.finder AppleShowAllFiles -bool true
隐藏Mac隐藏文件的命令:defaults write com.apple.finder AppleShowAllFiles -bool false
怎样找到应用程序的沙河路径:
每个沙盒中都有3个文件夹:1.Documents 2.Library 3.tmp
Documents:程序中建立的或在程序中浏览到的文件数据保存在该目录下,iTunes备份和恢复的时候会包括此目录
Library:存储程序的默认设置或其它状态信息;
Library/Caches:存放缓存文件,iTunes不会备份此目录,此目录下文件不会在应用退出删除
tmp:提供一个即时创建临时文件的地方。
itunes在与iphone同步时,备份所有的Documents和Library文件。
iphone在重启时,会丢弃所有的tmp文件。
十二、程序多语言支持或者经常程序会丢失Info.Plist.String(Chinese):
在工程里PROJECT------Localizations下边有个加号,点击一下就会出来很多国家的plist.string文件
十三、检测网路:
用第三方框架NetworkChecker来判断,代码如下,首先引入头文件
#import "NetworkChecker.h"
然后在.h里定义一个实例方法
-(BOOL)checkNetwork;
在.m文件中写
- (BOOL)checkNetwork { NetworkChecker *networkchecker = [NetworkChecker sharedNetworkChecker]; if ([networkchecker networkStatus] == NotReachable) { return NO;//返回NO是没网状态 } else { return YES;//返回YES是有网状态 } }
写完后当要用到判断网络的地方,这样写
if (![self checkNetwork]) { //当没有网络时执行的方法 }else{ //有网情况下执行方法 }
十四、用Blocks写网络请求:
NSString * str = [NSString stringWithFormat:@"http://star.eliteworkltd.com:8002/?json=1&p=1413"]; NSURL * url = [NSURL URLWithString:str]; //__block的作用是能在setCompletionBlock的内部访问外部的方法 __block ASIHTTPRequest * request = [ASIHTTPRequest requestWithURL:url]; [request setRequestMethod:@"GET"]; [request setCompletionBlock:^{ //相当于ASi的RequestFinished方法 }]; [request setFailedBlock:^{ //相当于ASI的RequestFailed方法 UIAlertView * alert = [[UIAlertView alloc]initWithTitle:@"亲" message:@"非常抱歉" delegate:nil cancelButtonTitle:@"您的网络不给力(︶︿︶)。。。" otherButtonTitles:nil, nil]; [alert show]; [alert release]; }]; //启动异步执行 [request startAsynchronous];
十五、SDWebImage:
跟以前的AsycImage用法有些相似,只用给一个图片的url地址即可,sdweb会自动帮你读出图片并且缓存,sdweb和Asy不同之处是sdweb需要给一张占位图,在图片没加载出来之前会先显示这张占位图。sdweb里边有个UIImageView+WebCache类,它是一个继承imageview的类目,在.m文件中引入头文件
#import "UIImageView+WebCache.h"
用法
[cell.imageview2 setImageWithURL:[NSURL URLWithString:url] placeholderImage:[UIImage imageNamed:@"57.png"]];
十六、截取当前页面到相册:
需要添加QuartzCore.framework框架,并且引入头文件
#import <QuartzCore/QuartzCore.h>
//保存图片到相册 UIGraphicsBeginImageContext(self.view.bounds.size);//当前视图 [self.view.layer renderInContext:UIGraphicsGetCurrentContext()]; UIImage * viewImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); UIImageWriteToSavedPhotosAlbum(viewImage, nil, nil, nil); UIAlertView * alert = [[UIAlertView alloc]initWithTitle:@"亲" message:@"图片已经为您保存到相册" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil]; [alert show]; [alert release];
十七、在程序内发邮件:
在程序内发送Email,需要添加MessageUI.framework框架,import头文件,加MFMailComposeViewControllerDelegate代理
#import <MessageUI/MFMailComposeViewController.h> @interface DetailViewController : UIViewController<MFMailComposeViewControllerDelegate> { } @end
然后调用方法:
//激活邮件功能 [self sendMailInApp];
然后在下边写sendMailInApp方法
#pragma mark ------- Send Email -(void)sendMailInApp { Class mailClass = (NSClassFromString(@"MFMailComposeViewController")); if (mailClass != nil) { if ([mailClass canSendMail]) { [self displayComposerSheet]; }else { [self launchMailAppOnDevice]; } } else { [self launchMailAppOnDevice]; } } -(void)displayComposerSheet { MFMailComposeViewController * mailPicker = [[[MFMailComposeViewController alloc]init] autorelease]; mailPicker.mailComposeDelegate = self; //设置主题 [mailPicker setSubject:[NSString stringWithFormat:@"%@%@%@%@",@"分享自张梦格APP",@"《",self.titleString,@"》"]]; //添加发送者 NSArray * toRecipients = [NSArray arrayWithObject:@"first@example.com"]; [mailPicker setToRecipients:toRecipients]; /* //email正文里添加图片 UIImage * addPic = [UIImage imageNamed:@"123.jpg"]; NSData * imageData = UIImagePNGRepresentation(addPic); [mailPicker addAttachmentData:imageData mimeType:@"" fileName:@"123.jpg"]; */ NSString * emailBody = nil; [mailPicker setMessageBody:emailBody isHTML:YES]; [self presentModalViewController:mailPicker animated:YES]; } -(void)launchMailAppOnDevice { NSString * recipients = @"mailto:first@example.com&subject=my email!"; NSString * body = @"&body=email body!"; NSString * email = [NSString stringWithFormat:@"%@%@",recipients,body]; email = [email stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; [[UIApplication sharedApplication]openURL:[NSURL URLWithString:email]]; } -(void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error { NSString * message; switch (result) { case MFMailComposeResultCancelled://用户取消编辑邮件 message = @"邮件发送取消"; break; case MFMailComposeResultSaved: //用户成功保存邮件 message = @"邮件保存成功"; break; case MFMailComposeResultSent: //用户点击发送,将邮件放到队列中 message = @"邮件发送成功"; break; case MFMailComposeResultFailed: //用户试图保存或者发送邮件失败 message = @"邮件发送失败"; break; default: break; } DLog(@"%@", message); [self dismissModalViewControllerAnimated:YES]; }
十八、iphone开发的一些总结(原文出自编程神人老莫):
1.Done is better than perfect(尤其是程序第一次提交,不要想着把东西做的多好多炫多么天花乱坠之后在上线,一定要以一个简单又能通过的方式先提交第一版,然后在做第二版更新);
2.优先、尽早的学习苹果的新技术,因为你迟早都是要学的;
3.好的平面设计不等于好的iphone设计,web的一套设计在移动设备上并不适用;
4.选择被证实的成功上线案列走,因为前人已经为你走过无数次的reject之路;
5.你的app要值得用户反复去用,要区别于同类产品。
十九、最后总结几点苹果审核几个要点(都是经过血泪的教训才总结出来的经验),不遵循这些规则你的应用很可能被打回:
1.我的应用第一次被打回来苹果给了原因是服务器太慢,程序里的图片出不来,后来换了服务器,并且在代码上做了优化;第二次又被驳回,苹果给你的原因是not very useful,Simply web sites bundled as apps,苹果认为程序过于简单,就跟一个web的应用一样;don’t provide any lasting entertainment value(不能提供任何的持续的娱乐价值) ,后来把程序主题框架换成了Path菜单,又加入了用户留言板功能才通过。
2.bug和崩溃:首先最重要一点提交的程序一定不能有bug和崩溃,如果有必定会被打回。
3.条款违规:不符合国家法律规定的,含有严重暴力色情内容的。
4.侵权:也就是说不要有侵权行为或者是窃取用户隐私,被发现的化一定会被打回。
5.功能描述与事实不符,软件说明上吹的多牛X多牛叉,实际上根本就没有 。
6.不能用苹果私有的API
7.山寨:抄袭别人软件创意,严重雷同
8.软件功能不能影响苹果自己的产品,抢苹果生意的,最后都会被pass