月度存档: 九月 2017

xcode9 打包报错问题解决

xcodebuild -workspace HuLaVenue.xcworkspace -scheme HLCG -configuration Debug clean -archivePath /目录/HuLaVenue-dev-315 archive CODE_SIGN_IDENTITY=”iPhone Developer: xxxxxxxx” PROVISIONING_PROFILE=”UUIDUUIDUUIDUUIDUUIDUUID”

xcodebuild -exportArchive -archivePath /目录/HuLaVenue-dev-315.xcarchive -exportPath /目录/build -exportOptionsPlist /目录/export-dev.plist

2017-09-21 15:18:04.806 xcodebuild[8273:56611] [MT] IDEDistribution: -[IDEDistributionLogging _createLoggingBundleAtPath:]: Created bundle at path ‘/var/folders/d7/cpr_njpd7_gf29sww6x6k0pc0000gn/T/HLCG_2017-09-21_15-18-04.806.xcdistributionlogs’.
2017-09-21 15:18:05.405 xcodebuild[8273:56611] [MT] IDEDistribution: Step failed: <IDEDistributionSigningAssetsStep: 0x7f820c1584e0>: Error Domain=IDEDistributionSigningAssetStepErrorDomain Code=0 “Locating signing assets failed.” UserInfo={NSLocalizedDescription=Locating signing assets failed., IDEDistributionSigningAssetStepUnderlyingErrors=(
“Error Domain=IDEProvisioningErrorDomain Code=9 \”\”HLCG.app\” requires a provisioning profile with the Associated Domains and Push Notifications features.\” UserInfo={NSLocalizedDescription=\”HLCG.app\” requires a provisioning profile with the Associated Domains and Push Notifications features., NSLocalizedRecoverySuggestion=Add a profile to the \”provisioningProfiles\” dictionary in your Export Options property list.}”
)}
error: exportArchive: “HLCG.app” requires a provisioning profile with the Associated Domains and Push Notifications features.

Error Domain=IDEProvisioningErrorDomain Code=9 “”HLCG.app” requires a provisioning profile with the Associated Domains and Push Notifications features.” UserInfo={NSLocalizedDescription=”HLCG.app” requires a provisioning profile with the Associated Domains and Push Notifications features., NSLocalizedRecoverySuggestion=Add a profile to the “provisioningProfiles” dictionary in your Export Options property list.}

** EXPORT FAILED **

Build step ‘Execute shell’ marked build as failure
Finished: FAILURE

 

 

解决办法:编辑plist文件 添加
解决办法:编辑plist文件 添加
<key>provisioningProfiles</key>
<dict> <key>com.hula.xxxxxx</key>
<string>HulaVenueDev</string> (此处名字获得见下文)
</dict>

如:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>  
	<key>provisioningProfiles</key>
	<dict>
		<key>com.hula.xxxxxx</key>
        <string>HulaVenueDev</string>
	</dict>
    <key>compileBitcode</key>  
    <false/>
    <key>teamID</key>
	<string>teamIDteamIDteamID</string>
    <key>method</key>  
    <string>development</string> 
    <key>uploadSymbols</key>
    <true/> 
</dict>
</plist>

provisioningProfile名可以在apple deveploer后台获得。也可以在mobileprovision文件中获得。
如图:

或 less dev.mobileprovision 找到Name

Objective-C Runtime

一、简介

Runtime,Objecive-c运行时,一套底层C语言的API。
我们平常写的OC底层都是基于Runtime来实现的, 例如:

//注意使用以下代码,请在xcode工程设置中找到Enable Strict Checking of objc_msgSend Calls并关闭该选项。
[self tryUpgradeApp];
//其实会转化为
objc_msgSend(self, @selector(tryUpgradeApp));

//如有参数:
[self tryUpgradeApp:arg1...];
//则转为
objc_msgSend(self, @selector(tryUpgradeApp), arg1, ...);

消息是直到运行的时候才和方法实现绑定的,编译器会把一个消息表达式转化成一个objc_msgSend的调用,该方法主要参数有消息接受者和方法标号,同时有可变参数可以接受相应的参数。

多数情况下开发者只需要编写objc代码即可,编译器会将objc代码转为runtime代码,在运行时确定数据结构和函数。

@implementation TestCls

+(instancetype) create
{
   TestCls* instance = [[[self class] alloc] init];
    [instance onCreate];
    return instance;
}

-(void) onCreate{
    NSLog(@"onCreate >> in >>");
}

@end

执行以下命令得到一个cpp文件。

clang -rewrite-objc TestCls.m 

生成的文件很大我们只看以下内容,从下代码可以看到,实际上objc的方法调用都是用过objc_msgSend消息机制实现的。

static __NSConstantStringImpl __NSConstantStringImpl__var_folders__9_4xdmxtdd1sv16b8cry0qlxzm0000gn_T_TestCls_b47c1a_mi_0 __attribute__ ((section ("__DATA, __cfstring"))) = {__CFConstantStringClassReference,0x000007c8,"onCreate >> in >>",17};

static instancetype _C_TestCls_create(Class self, SEL _cmd) {
   TestCls* instance = ((id (*)(id, SEL))(void *)objc_msgSend)((id)((id (*)(id, SEL))(void *)objc_msgSend)((id)((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("class")), sel_registerName("alloc")), sel_registerName("init"));
    ((void (*)(id, SEL))(void *)objc_msgSend)((id)instance, sel_registerName("onCreate"));
    return instance;
}

static void _I_TestCls_onCreate(TestCls * self, SEL _cmd) {
    NSLog((NSString *)&__NSConstantStringImpl__var_folders__9_4xdmxtdd1sv16b8cry0qlxzm0000gn_T_TestCls_b47c1a_mi_0);
}

二、runtime的数据结构

// 参考 objc/objc.h 

// id 
struct objc_object {
    Class isa  OBJC_ISA_AVAILABILITY;
};
typedef struct objc_object *id;



//sel
typedef struct objc_selector *SEL;

// class
typedef struct objc_class *Class;

struct objc_class {
    //class中也有一个isa指针指向所属的元类
    Class isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
   //指向父类
    Class super_class                                        OBJC2_UNAVAILABLE;
   //类名
    const char *name                                         OBJC2_UNAVAILABLE;
   //类的版本信息
    long version                                             OBJC2_UNAVAILABLE;
   //信息
    long info                                                OBJC2_UNAVAILABLE;
   //实例大小
    long instance_size                                       OBJC2_UNAVAILABLE;
   //成员变量列表
    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;
   //成员方法列表
    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;
   //系统调用的方法会缓存到cache中使调下次调用效率更高
    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;
   //该类实现的协议列表
    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;
#endif

继续阅读 »

排序算法:归并排序

归并排序的思路是 采用分治法,将一个大的问题拆分成若干个小问题,将一个大数组 拆为多个小数组进行排序 后再进去重组。 入下图锁示

拼合2个数组的思路:因为2个数组其实都是排过序的,只要给2个数组都设置个游标可以跟简单的进行组合。如下图所示



 

实现代码: 继续阅读 »

排序算法:插入排序

插入排序的思路为: 每一步都将一个待排序的元素插入到排好序的数组中的相应位置,知道所有元素都插入完为止。如下图所示:

代码如下:
继续阅读 »

排序算法:快速排序 QuickSort

快速排序的的基本思路是: 通过一次排序,将数组分割为   参考值(1个值)、较大(比参考值都大的一群)、较小值(比参考值度小的一群) 3部分。然后将较大的部分和较小的部分视为2个数组进行再次排序,整个排序过程使用递归进行,以此达到整个数组的排列。  如下图:

在排序过程中可以设置任意一个数组元素为参考值,但是为了遍历的方便性 可以采用头尾使代码更简单,上图r(最后一个元素)为参考值。

j指针为每次遍历的下标,i指针则标识分隔符i之前的素组则都比r小,i之后的则都比r大,
每次遍历j都和r比较,如果j < r则进行i 和j的交换然后i的指针+1 , 到最后一轮时,r和i进行交换,则形成一个结果  比 [r小的区域,  r , 比r大的区域]  依次再次对左右2个区域进行相同的处理。

代码如下…
继续阅读 »