摄影师张梦格App项目总结

 

     昨天张梦格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

 

 

 

 

 

 

 

 

posted @ 2013-01-23 15:17  单眼皮的芒果  阅读(1035)  评论(0编辑  收藏  举报