存档

‘iOS’ 分类的存档

objective-c和swift相互调用

2015年5月5日 没有评论

自从苹果推出swift语言,已经过去好几个版本了,现在是时候考虑使用swift语言了。

在objective-c和swift相互调用的过程中,有一个很重要的文件,名称为<ProjectName>-Bridging-Header.h,假设我们的项目名称为 Laodaoxia,那么对应的文件名就是 Laodaoxia-Bridging-Header.h。这个文件第一次是由XCode自动生成的,这个文件负责完成2种不同的语言之间的转换。

现阶段,很多项目都是由objective-c创建的,当为他们添加新功能时,可以使用swift来编写。衣服自己洗先来说下如何添加swift支持。我们在项目中添加由swift文件,如果是第一次添加swift的话,IDE会提示你是否要创建桥接文件,点击是。此时,项目中会新增2个文件,一个是swift文件,一个是桥接文件。如果不小心删除了桥接文件,也可以手动创建一个,只要名称是符合上面的规定即可。

然后在swift文件中该怎么写代码就怎么写代码好了。对于 objective-c 文件,如果要调用swfit方法,则在对应的m文件里添加引用,#import “Laodaoxia-Swift.h”,剩下的就可以按照普通的 objective-c 的语法来调用swift 的方法了。<ProjectName>-Swift.h 文件应该是一个隐藏的文件,XCode负责把项目中的swift文件类通过该文件来提供给objective-c文件调用。

至于swift项目,要添加objective-c代码,例如很多通用库等等,也是差不多的步骤。项目中添加objective-c的类,第一次添加时,IDE会询问是否要添加桥接文件,同意添加后,项目中会新增对应的h文件,m文件和桥接文件。把swift会用到的objective-c类的头文件,全部使用#import假如到桥接文件里。

添加完成后,即可在swift代码里使用swift语法格式来使用objective-c提供的方法了。

分类: iOS 标签: , ,

pod setup 失败解决

2014年12月11日 没有评论

cocoapods 是 iOS 上不错的包依赖管理软件,在前面的文章里衣服自己洗是有做简单的介绍。

苹果发布了Mac OS X 10.10 后,就安装了新系统和 XCode 6,然后顺便执行了 sudo gem update –system

然后噩梦就来了,这次要创建一个新的项目,写好 podfile 后,结果安装失败。然后网上一搜索,发现 OS X 10.10后有点问题,需要先卸载 cocoapods,然后再重新安装。各种细节和其它诸如Command Line Tools之类的就不展开说了。

安装倒是成功了,可是在执行 pod setup时,总是失败。提示 There was an error reading ‘/Users/mmcer/.cocoapods/repos/master/CocoaPods-version.yml ,然后给了一个官方的URL地址。

按照该地址访问 http://blog.cocoapods.org/Repairing-Our-Broken-Specs-Repository/,使用里面的方法删除本地文件夹

sudo rm -rf ~/.cocoapods/repo/master/
sudo setup

仍然失败,衣服自己洗以为是网络、CDN或者国家防火墙的问题,于是回家后又是各种环境,还是不行。网上是各种搜索,大家的解决方法和上面的几乎是一样的。

后来就闲逛github,在他们的 issue 里发现了居然别人也有相同的问题,并且自己摸索解决了。这里真是要汗颜下自己,没有一早想到这里不说,还懒的自己去摸索。

原因就是曾经的更新导致,具体就是 psych 这个组件,卸载然后安装一个低版本就可以了。github 里是用的2.0.0,但是我用了一个略高的版本发现也是可以的。

sudo gem uninstall psych
sudo gem install psych -v 2.0.0

帖子里还有个人是把所有的gem安装的软件都卸载了然后重装发现也可以解决问题,衣服自己洗觉得太麻烦就没有采用。

之后再重新执行 pod setup 和 pod install 都正常了。浪费了3天时间,对进度还是有很大影响的,不过这个是题外话了。

分类: iOS, 一句话, 日常 标签: , , ,

iOS使用keychain存储数据

2014年9月23日 没有评论

在某个周六的时候,我跑去听了一个淘宝举办的无线交流会,对于安全来说还是蛮有收获的。回来后在网上找相关资料,看到一个关于使用 keychain 来存储数据的方案,思路比较不错。

使用keychain,有2点好处。

1、数据相对使用NSUserDefaults,更安全一点。

2、可以用来进行应用间的数据共享。

下面给出通用类代码,首先是头文件

KeychainManager.h

 

#import <Foundation/Foundation.h>

@interface KeychainManager : NSObject

+ (void)save:(NSString *)key withValue:(id)value;

+ (id)get:(NSString *)key;

+ (void)deleteData;

@end

接下来,是具体的实现代码

KeychainManager.m

#import “KeychainManager.h”

@implementation KeychainManager

static NSString * const KEY_IN_KEYCHAIN = @”com.5danyuan.app”;

+ (void)save:(NSString *)key withValue:(id)value{

    NSMutableDictionary *dic = [NSMutableDictionary dictionary];

    

    [dic setObject:value forKey:key];

    

    NSMutableDictionary *query = [NSMutableDictionary dictionaryWithObjectsAndKeys:

                                  (__bridge_transfer id)kSecClassGenericPassword,

                                  (__bridge_transfer id)kSecClass,

                                  KEY_IN_KEYCHAIN,(__bridge_transfer id)kSecAttrService,

                                  KEY_IN_KEYCHAIN,(__bridge_transfer id)kSecAttrAccount,

                                  (__bridge_transfer id)kSecAttrAccessibleAfterFirstUnlock,

                                  (__bridge_transfer id)kSecAttrAccessible,

                                  nil];

    //删除旧数据

    SecItemDelete((__bridge_retained CFDictionaryRef)query);

    [query setObject:[NSKeyedArchiver archivedDataWithRootObject:dic] forKey: (__bridge_transfer id)kSecValueData];

    SecItemAdd((__bridge_retained CFDictionaryRef)query, NULL);

}

+ (id)get:(NSString *)key{

    NSMutableDictionary *dic = nil;

    NSMutableDictionary *query = [NSMutableDictionary dictionaryWithObjectsAndKeys:

                                  (__bridge_transfer id)kSecClassGenericPassword,

                                  (__bridge_transfer id)kSecClass,

                                  KEY_IN_KEYCHAIN,(__bridge_transfer id)kSecAttrService,

                                  KEY_IN_KEYCHAIN,(__bridge_transfer id)kSecAttrAccount,

                                  (__bridge_transfer id)kSecAttrAccessibleAfterFirstUnlock,

                                  (__bridge_transfer id)kSecAttrAccessible,

                                  nil];

    [query setObject: (id)kCFBooleanTrue forKey: (__bridge_transfer id)kSecReturnData];

    [query setObject: (__bridge_transfer id)kSecMatchLimitOne forKey: (__bridge_transfer id)kSecMatchLimit];

    CFDataRef keyData = NULL;

    if (SecItemCopyMatching((__bridge_retained CFDictionaryRef)query, (CFTypeRef *)&keyData) == noErr) {

        @try {

            dic = (NSMutableDictionary *)[NSKeyedUnarchiver unarchiveObjectWithData: (__bridge_transfer NSData *)keyData];

        }

        @catch (NSException *exception) {

            NSLog(@”Unarchive of %@ failed:%@”,KEY_IN_KEYCHAIN,exception);

        }

        @finally {

            

        }

    }

    

    if(dic != nil){

        return [dic objectForKey:key];

    }

    

    return nil;

}

+ (void)deleteData{

    NSMutableDictionary *query = [NSMutableDictionary dictionaryWithObjectsAndKeys:

                                  (__bridge_transfer id)kSecClassGenericPassword,

                                  (__bridge_transfer id)kSecClass,

                                  KEY_IN_KEYCHAIN,(__bridge_transfer id)kSecAttrService,

                                  KEY_IN_KEYCHAIN,(__bridge_transfer id)kSecAttrAccount,

                                  (__bridge_transfer id)kSecAttrAccessibleAfterFirstUnlock,

                                  (__bridge_transfer id)kSecAttrAccessible,

                                  nil];

    

    SecItemDelete((__bridge_retained CFDictionaryRef)query);

}

@end

 对于通用类而言,提供了3个方法,添加、删除、保存。其中,为了安全起见,防止被恶意分析,获取的get方法的返回值是 id 类型的。对于合法的使用者,自然是知道应该转换为什么样的数据类型的。

分类: iOS, 日常 标签: , , ,

Pull is not possible because you have unmerged files解决方法

2014年3月2日 没有评论

最近在项目中添加了一个 SDWebImage 开源组件,然后运行 pod install的时候,结果出现了Pull is not possible because you have unmerged files 错误提示。

删除然后重新安装,依然报错。解决方法如下:

pod repo remove master

pod setup

如果仍然没有效果,那么再清理下缓存

rm -rf ~/.coocapods/

pod setup

我这边只进行了上面的第一步就已经正常了。

分类: iOS, 日常 标签: ,

iOS第三方库管理工具:CocoaPods

2013年12月3日 没有评论

iOS 开发是我自学的,就那种边学边用的那种。一切都是慢慢摸索。

以前有看到推荐CocoaPods,一看介绍,确实不错,值得一用,但是直到今天才自己为此写文字。

现在来说流程:

首先在命令行里执行如下操作:

1、sudo gem update –system

这是为了让系统组件升级到最新版本。

2、sudo gem install cocoapods

开始安装cocoapods。

3、pod setup

自动配置cocoapods。接下来呢,就是要针对每个 ios 项目了。在想要配置的项目里编辑文件,文件名为 Podfile,内容格式如下:

platform     :ios
pod ‘JSONKit’
pod ‘FMDB’

这里需要特别说明的是,第一行的冒号应该和 ios 放在一起,我最开始是放在前面的,导致出错。剩下的就是每一行一个第三方的库引用。如果不知道名称是什么,可以用   pod search 关键词  命令来搜索看看。其实 Podfile 文件也可以使用touch 命令来创建,但是我更喜欢用编辑器来操作。其实后面还可以跟版本号,我比较喜欢使用最新的版本,所以就去掉啦。文件创建完成后,就执行第四步。

4、pod install

这个命令是需要先在命令行里进入到项目的文件夹,然后才运行的。安装成功后,会在项目的目录中,多出3个文件和一个文件夹,分别是  ***.xcworkspace、Podfile、Podfile.lock、Pods。以后再打开项目的话,就不要用 ***.xcodeproj 了,而是改用 ***.xcworkspace 。

随着项目的进度,会在后面才加入新的第三方库,这个时候只需要在 Podfile 里添加新的行,然后命令行进入到对应的项目文件夹,执行 pod update 就可以了。其实重新执行 pod install 也没有太大影响,只是说相对会慢一点。

上面的步骤和网上其他的地方基本上是大同小异的,实际使用的过程中,我还发现了另外的一个问题,就是在打开项目的时候,XCode 会提示我要不要对文件进行解锁。解锁后,总是提示失败。正是这个原因导致我在开始的时候放弃了CocoaPods。

我不知道这个现象是不是只有我一个人才有,网上也搜索了下,似乎信息很少。有的同学会觉得奇怪,既然无法解锁,那么就不解锁呗。原因是酱紫的,因为第三方库可能存在bug,或者使用了被遗弃掉的API,或者兼容性问题,或者只需要使用其中的某一个子组件。这些情况下,就需要对第三方库进行修改和完善。如果不解锁,就无法保存修改的地方。

既然没有什么有效的方式来解锁,只好使用linux的功能,sudo chmod -R 777  目录名   。这样的话就可以解锁所有的目录了。-R 参数是遍历所有的子目录。先前我每天添加,解锁不完美,后来查询了参数就顺利解决了。

在最后还有一个很重要的步骤,就是添加引用,不然在项目的代码里是无法 #import 头文件的,打开项目的 Target ,选择Build Settings,然后在Search Paths 节点下 User Header Search Paths 添加一个配置 ${SRCROOT},同时要记得选择 recursive。如果你一时发现不了User Header Search Paths,可以善用上方的搜索条喔。

分类: iOS, 日常 标签: , ,

ios 7 导航栏遮挡视图的问题

2013年10月9日 没有评论

在发布了新的 ios 7 系统后,发现导航栏会占据视图的位置,如果应用是在6 和7 上都有用户的话,那么就需要做兼容适配。

网上有看到2种方法。一种是设置 UINavigationBar的translucent属性,self.navigationController.navigationBar.translucent = NO;

另外的一个方法是设置边沿延伸的属性,但是需要先获取判断系统的版本,代码如下:

if ([[[UIDevice currentDevice] systemVersion] doubleValue] >= 7.0) {

self.edgesForExtendedLayout = UIRectEdgeNone;

}

 

在查看文档的时候,发现有段文字提及UINavigtaionBar的高度会自动根据实际情况变化为 44 或者64,没有确定的预测方法,如果对 UINavigationBar 有设置背景图片的话,按照别人的经验,最好是用一个64高度的图片,上面的20像素设置为透明的。更具体的内容可以查看这里

分类: iOS, 日常 标签: ,

iOS应用开发价格有多低

2013年7月22日 没有评论

7月份都过去大半了,今天才来写这个月的博客。今天可以来说一说最近发生的一件事情。

这个月,除了玩了很多的LOL外,就是写一个小应用了。某一次在威客网站上接了一个iOS的活,人家已经有android 的版本了,想再来一个iOS的,功能都比较简单。人家问我要多少钱,我很不自信,因为才学习iOS开发没有多久,所以准备说200块。然后又一狠心,又加了50块。

接着就轮到人家不相信了,我想如果从事开发的同学就知道,这个价格是非常低的了。在人家质疑能力的时候,幸好前不久在store上架了一个html5介绍的应用,于是人家也没有多说什么,当然这么低的价格也让人家最终选择了我。

当然最后结果还是不错的,人家主动说250块太低了,然后给加到350块了,后来觉得和我合作很舒服,于是又给添加了350块。虽然钱真的不多,也就一顿饭的支出。但那种被认可的感觉,真的很爽。

因为这个事情,妹子把我说了好几顿了。正所谓万事开头难嘛~再接再励好了。

分类: iOS, 日常 标签: ,

解决a valid provisioning profile for this executable was not found

2013年6月7日 没有评论

今天拿到一个 pad mini,所以就想看看糗事在pad 上运行的效果是什么样子的。先在网页上添加了设备的唯一编号,然后运行。结果就报错,弹出错误提示为 “a valid provisioning profile for this executable was not found”。

网上查询了下,大致都是说证书的问题,我印象只是记得在 xcode 的界面中曾提示过什么密码不正确。后来又查看了 provisioning profile ,发现果然没有选择新添加的设备。勾选并重新生成证书,下载安装。问题解决了。

分类: iOS, 一句话 标签:

第一个iOS应用上架

2013年6月7日 没有评论

第一个iOS应用终于上架了。这是一个分享传播html5知识的简单应用。历时3个月,被拒绝了5次。通过审核时,真是感觉泪流满面啊。

由于E文水平很菜,当初想了解下苹果从开发到上架的整个流程,于是就想写一个简单的应用尝试看一看。我的很多朋友都是在做前端开发,所以就选择以 html5 作为切入点。

其实最头疼的是没有设计参与进来,所以界面简单而且丑陋。苹果的审核是很严格的,对于不会做设计的我来说,实在是有点难为我。由于程序功能简单,网上很多的界面都只有参考意义。

后来有一次看到微博上一个讲述统计的图片,有点感觉,于是使用了四叶草的变形。也恰好符合程序的几个功能菜单。在最开始的版本里,有放一个广告墙的推荐。被拒绝后在原因描述里说违反了苹果的策略。按说在应用里放广告是很正常的事情,不知道为什么会拒绝。只好给移除掉。

位置是空闲出来了,但是接下来要考虑填充的内容,恰好在看一个 cover flow的特效,那天在家在翻阅一本前端开发的书籍,当时就决定使用这个特效来推荐一些关于 html5的书籍。于是也就有了现在的样子。

应用最初出发点是想熟悉流程的,被苹果拒绝后,看着页面上显示 reject 字样,有点强迫症的我,又开始不甘心了,坚持要给做到通过。是的,最后我坚持下来了,不知道是不是因为他们的审核团队比较烦我才给通过的。

丑是丑了点,我接受各位同学的鄙视,不过你们谁有比较好的设计资源,一定要告诉我呀。

分类: iOS, 一句话 标签: ,

iOS 默认英文语言误删除的恢复

2013年5月30日 没有评论

上一个应用中的下拉刷新我是自己摸索着写的,不过是针对 UITableView 的,这次的应用是要针对一个 UIScrollView ,就想用现成的,反正大概原理都差不多,没有必要重复造轮子。于是选择了 EGORefreshTableHeaderView 。

下午就边网上搜索边尝试使用,但是发现这个组件里的文字使用了多语言设置,诶呀我去,我的应用根本不需要多语言,估计写代码的多少都和我一样有点强迫症,于是按照它的结构来添加多语言处理,没有修改源码,顺便就当学习下如何使用多语言呗。

添加语言时,弹出了一个对话框,大概是问是不是要引用系统默认的英文。一想应用又不上国外市场,要着毛用。就取消,然后选择英文,点击删除。列表里干净了,洁癖的人你伤不起。准备添加中文,但是这个时候添加不了了。

对话框里只有一个 Choose files and reference language to create **** localization ,无法下一步了,在这下班的点来了这么下,网上一顿好找,google 时不时和谐,后来终于在 stackoverflow  的某个网页上发现了方法,现在放出来,方便和我一样E文是个半吊子的人。

右键点击*.xcodeproj 文件,选择显示包内容,然后编辑 project.pbxproj 文件,搜索/* End PBXSourcesBuildPhase section */字符,在这个段落的后面添加一个新的段落如下:

/* Begin PBXVariantGroup section */
27548D921611B0BE008EA1CD /* Localizable.strings */ = {
isa = PBXVariantGroup;
children = (
27548D941611B0BE008EA1CD /* en */,
);
name = Localizable.strings;
path = ../Code;
sourceTree = “<group>”;
};
/* End PBXVariantGroup section */

到这里都还算简单,后面的步骤我是摸索了才明白。

接下来,在项目中添加 Localizable.strings 资源文件,然后在project.pbxproj文件中搜索 /* Localizable.strings in Resources */ 字符串,找到前面的字符串标志,替换我红色标记的部分。记得喔,绿色部分的不要替换,我给替换了然后 xcode 直接崩溃掉。蓝色部分的 path 我就不清楚啥意思了,原帖中只是说让大家自己尝试就知道什么情况了。我看了下project.pbxproj里其它地方对于 Localizable.strings 文件有 path 关键字的描述,最后给修改成 Localizable.strings 这个字符串了,而非上面的 ../Code。

重新打开项目,系统默认的语言就又回来了。接下来就是该怎么办就怎么办了,真长姿势。

后面的总结就是,XCode 真心木有 VS 好用。

分类: iOS 标签: , ,