
2015,Objective-C的这些新改变
当众人的目光聚焦在WWDC 2015新推出的Swift 2和iOS 9上时,还有多少人会想起自己初入iOS开发时所看的那一本本Objective-C 资料,如今Objective-C 的种种局限已不复存在,2015年的Objective-C 以全新的面貌重新出现在我们眼前,下面就来看看这位熟悉的旧友有了哪些改变吧。
会弱化Swift代码和可读性
很遗憾,Swift支持泛型(generics)就意味着Objective-C 只会以optional的AnyObject集合的形式出现。如此一来,开发者要使用该属性就必须在Swift和Objective-C之间进行转换。
Nullability Annotations
单单一个属性就引发了这么多担忧,还挺让人不安的。如果代码本身引发很多质疑,出现error的可能性就大大增加,更别提在广为熟知的Objective-C和语言新秀Swift之间相互调用(interoperability)了。现在有了nullability annotations,问题就简单多了,编程也会省下很多麻烦。
@property (strong, nonatomic, nonnull) NSArray *someViews;
intent.大大提升了Objective-C,而且这个属性也不会在Swift里满满都是optional了,开发者看看代码就知道有没有nil pointer了。计算机的静态检验和Swift的可用性都得到了提升,最重要的是实现了API的intent通讯。
泛型的出现,泛型的缺席一直以来是Objective-C开发者心头之痛,而诞生32年之后,Objective-C终于也支持泛型了,支持泛型将带来诸多改变,而且都是积极的改变。
现在可以定义属性,下指令给编译器来显示所有UIView:
@property (strong, nonatomic, nonnull) NSArray<UIView > someViews;
向属性强加UIView之外的东西时,编译器会报错,而且如今不用做大量头痛的转换(cast)了。
Objective-C支持泛型对Swift而言也是好消息。上次更新时,让Swift知道对象不应该是optional的,现在Swift还知道它们是UIViews,如此一来含混不清的AnyObject声明就不需要了。如今的Objective-C可以像C#、C++、Swift等语言一样通过<>括号来表示类型了。虽然通常是对协议表示一致性(conformance),但编译器知道何时、何地以及如何运用它们,且运用是经过推理的。
再进一步,可以用参数来表示扩展(extensions)、类别(categories)和类(classes),好处不仅仅体现在集合(collections)上。泛型的强大体现在整个Objective-C之中,集合仅仅是结果而已。
type erasure不但能实现二进制兼容,而且不改变Objective-C的执行时间。所以开发者们,C#的泛型的确胜过其他语言,这点依旧不会改变,所以发发牢骚就好了。
KindOf Types,再次调用之前定义的属性,就会显示UIView。判断里面包含着views和buttons是再正常不过的事。这种情况下,添加如下代码会发生什么呢?
[self.someViews[0]addTarget:selfaction:selector(aMethod:)
forControlEvents:UIControlEventTouchUpInside];
编译器警告,因为即便可以在这个属性里插入一个button,就算可以假设是个UIView,button也不一定没有经过转换,现在新的KindOf特性能够轻松解决这种始料未及的情况:
@property (strong, nonatomic, nonnull) NSArray<__kindof UIView > someViews;
实际上编译器已经知道了:属性及其集合会出现一些UIView。这样在类型协议里显示更多我们之前看不到的信息,其本质是向下转型(downcasting)。这意味着上述代码编译没什么问题,因为编译器知道集合里肯定会出现一个button,现在那些担忧就都解释得清了。
虽然不喜欢Swift的人可能会刻意夸大Objective-C的优点,但如今两种语言实现了互相调用,这是Objective-C所有提升的最大价值所在,毋庸置疑,Objective-C的确比以往更加强大。
虽然如今Swift正以迅雷不及掩耳之势蚕食着Objective-C,但Objective-C 对每一个iOS开发者来说,就如初恋一般的美好,因此如今Objective-C的提升对开发者而言,是件非常值得高兴的事,它能够帮助开发者写出更好的代码,而且这些优势已经在Foundation中随处可见了。
当众人的目光聚焦在WWDC 2015新推出的Swift 2和iOS 9上时,还有多少人会想起自己初入iOS开发时所看的那一本本Objective-C 资料,如今Objective-C 的种种局限已不复存在,2015年的Objective-C 以全新的面貌重新出现在我们眼前,下面就来看看这位熟悉的旧友有了哪些改变吧。
会弱化Swift代码和可读性
很遗憾,Swift支持泛型(generics)就意味着Objective-C 只会以optional的AnyObject集合的形式出现。如此一来,开发者要使用该属性就必须在Swift和Objective-C之间进行转换。
Nullability Annotations
单单一个属性就引发了这么多担忧,还挺让人不安的。如果代码本身引发很多质疑,出现error的可能性就大大增加,更别提在广为熟知的Objective-C和语言新秀Swift之间相互调用(interoperability)了。现在有了nullability annotations,问题就简单多了,编程也会省下很多麻烦。
@property (strong, nonatomic, nonnull) NSArray *someViews;
intent.大大提升了Objective-C,而且这个属性也不会在Swift里满满都是optional了,开发者看看代码就知道有没有nil pointer了。计算机的静态检验和Swift的可用性都得到了提升,最重要的是实现了API的intent通讯。
泛型的出现,泛型的缺席一直以来是Objective-C开发者心头之痛,而诞生32年之后,Objective-C终于也支持泛型了,支持泛型将带来诸多改变,而且都是积极的改变。
现在可以定义属性,下指令给编译器来显示所有UIView:
@property (strong, nonatomic, nonnull) NSArray<UIView > someViews;
向属性强加UIView之外的东西时,编译器会报错,而且如今不用做大量头痛的转换(cast)了。
Objective-C支持泛型对Swift而言也是好消息。上次更新时,让Swift知道对象不应该是optional的,现在Swift还知道它们是UIViews,如此一来含混不清的AnyObject声明就不需要了。如今的Objective-C可以像C#、C++、Swift等语言一样通过<>括号来表示类型了。虽然通常是对协议表示一致性(conformance),但编译器知道何时、何地以及如何运用它们,且运用是经过推理的。
再进一步,可以用参数来表示扩展(extensions)、类别(categories)和类(classes),好处不仅仅体现在集合(collections)上。泛型的强大体现在整个Objective-C之中,集合仅仅是结果而已。
type erasure不但能实现二进制兼容,而且不改变Objective-C的执行时间。所以开发者们,C#的泛型的确胜过其他语言,这点依旧不会改变,所以发发牢骚就好了。
KindOf Types,再次调用之前定义的属性,就会显示UIView。判断里面包含着views和buttons是再正常不过的事。这种情况下,添加如下代码会发生什么呢?
[self.someViews[0]addTarget:selfaction:selector(aMethod:)
forControlEvents:UIControlEventTouchUpInside];
编译器警告,因为即便可以在这个属性里插入一个button,就算可以假设是个UIView,button也不一定没有经过转换,现在新的KindOf特性能够轻松解决这种始料未及的情况:
@property (strong, nonatomic, nonnull) NSArray<__kindof UIView > someViews;
实际上编译器已经知道了:属性及其集合会出现一些UIView。这样在类型协议里显示更多我们之前看不到的信息,其本质是向下转型(downcasting)。这意味着上述代码编译没什么问题,因为编译器知道集合里肯定会出现一个button,现在那些担忧就都解释得清了。
虽然不喜欢Swift的人可能会刻意夸大Objective-C的优点,但如今两种语言实现了互相调用,这是Objective-C所有提升的最大价值所在,毋庸置疑,Objective-C的确比以往更加强大。
虽然如今Swift正以迅雷不及掩耳之势蚕食着Objective-C,但Objective-C 对每一个iOS开发者来说,就如初恋一般的美好,因此如今Objective-C的提升对开发者而言,是件非常值得高兴的事,它能够帮助开发者写出更好的代码,而且这些优势已经在Foundation中随处可见了。
收起阅读 »
Hbuilder移动app java开发微信支付-前后端要点
本人第一次在dcloud上写文章,写的不好,请大家多多包涵,觉得有帮助,感谢送分!!!其他的不多说,本文为解决hbuilder上开发app微信支付的诸多细节,因缺少文档带来的不便。
一.开发前准备:
1.首先必须在微信开放平台注册账号,认证开发者资质。附链接:https://open.weixin.qq.com/
- 新建移动应用,如果要跟微信公众号的账号同步,可以关联上公众账号.如图附件图1.

- 新建应用的要填写的应用签名和包名(这个后面说配置)
- 要为所建应用申请微信支付,申请成功之后,获取商户号以及微信支付签名串paysignkey(32位)以备用。
二,java服务端代码:
/**
- app微信支付 调用接口
- @return
-
@throws Exception
*/
public String getWxPayShopParameters()throws Exception{
BigDecimal totalAmt = new BigDecimal (getParameter("total"));
String notify_url = getUrl()+"/appshop/app_shop_api!notifywxPayment.action"; //支付成功通知路径
Setting setting = SettingUtil.getSetting();
String appId = setting.getShopAppId();//移动应用的appid
String paySignKey = setting.getShopAppPaySignKey();//微信支付签名串
String mch_id = setting.getShopPartnerId(); //商户号(微信支付申请的商户号)
String totalfee = totalAmt.multiply(new BigDecimal(100)).intValue() + ""; // 支付金额,单位为分
String nonce_str = WxUtil.CreateNoncestr(); //随机数
String body = getParameter("body"); //商品描述
String attach = appId; //附加数据
String out_trade_no = getParameter("out_trade_no"); //商户订单号
String spbill_create_ip = getRequest().getRemoteAddr(); //订单生成的机器 IP
String trade_type = "APP";//交易类型
SortedMap<String, String> packageParams = new TreeMap<String, String>();
packageParams.put("appid", appId);
packageParams.put("mch_id", mch_id);
packageParams.put("nonce_str", nonce_str);
if(body != null && body.length() > 15) {
body = body.substring(0, 10) + "...";
}
packageParams.put("body", body);
packageParams.put("attach", attach);
packageParams.put("out_trade_no", out_trade_no);
packageParams.put("total_fee", totalfee);
packageParams.put("fee_type", "CNY");//币种
packageParams.put("spbill_create_ip", spbill_create_ip);
packageParams.put("notify_url", notify_url);
packageParams.put("trade_type", trade_type);
//packageParams.put("openid", "oc3KnjpEVsQDDYWq-KHMSPDhOTwU");String sign = WxUtil.createSign(packageParams, paySignKey); packageParams.put("sign", sign);//打包签名 String xml = WxUtil.ArrayToXml(packageParams); log.info("packageParams:" + packageParams); Map<String, Object> dataMap = new HashMap(); try { dataMap = WxUtil.getPrepayId(xml); log.info("dataMap:" + dataMap); } catch (Exception e) { e.printStackTrace(); } if(!"SUCCESS".equals(dataMap.get("return_code")) || !"SUCCESS".equals(dataMap.get("result_code"))) { throw new RuntimeException("获取prepay_id失败!"); } String prepay_id = (String) dataMap.get("prepay_id"); //wxOrderInfo.setPrepayId(prepay_id); SortedMap<String, String> finalpackage = new TreeMap<String, String>(); String timestamp = String.valueOf(System.currentTimeMillis() / 1000); String nonceStr2 = nonce_str; //需要的参数如下: finalpackage.put("appid",appId); finalpackage.put("partnerid",mch_id); finalpackage.put("prepayid", prepay_id); finalpackage.put("package", "Sign=WXPay"); finalpackage.put("noncestr",nonceStr2); finalpackage.put("timestamp",timestamp); String paySign = WxUtil.createSign(finalpackage, paySignKey); finalpackage.put("sign", paySign); return ajax(finalpackage);
}
三,hbuilder页面逻辑代码:
<script type="text/javascript">
mui.init();
var channel = null;
var channels = null;
var pays={};
function plusReady(){
// 获取支付通道
plus.payment.getChannels(function(cs) {
channels = cs;
}, function(e) {
alert("获取支付通道失败:" + e.message);
});
}
document.addEventListener('plusready',plusReady,false);
var w=null;
var WXPAYSERVER='..../gateway/mui_pay!getWxPayShopParameters.action?payid=';
var ALIPAYSERVER='.../payservice?payid='
//调用支付
function pay(id,amount,sheetNo){
if(w){return;}//检查是否请求订单中
// 从服务器请求支付订单
var PAYSERVER = '';
if (id == 'alipay') {
PAYSERVER = ALIPAYSERVER;
} else if (id == 'wxpay') {
PAYSERVER = WXPAYSERVER;
} else {
plus.nativeUI.alert("不支持此支付通道!");
return;
}
//获取支付通道
for (var i in channels) {
if (channels[i].id == id) {
channel = channels[i];
}
}
w=plus.nativeUI.showWaiting();
//获取支付通道
mui.get(PAYSERVER, {
total: 0.01,//支付费用
body: "测试支付",
out_trade_no:sheetNo
}, function(data) {
var varpay = {//参数顺序必须正确
retcode: 0,//5+必备参数
retmsg: "ok",//5+必备参数
appid: data.appid,
noncestr: data.noncestr,
package: "Sign=WXPay",
partnerid: data.partnerid,
prepayid: data.prepayid,
timestamp: data.timestamp,
sign: data.sign
}
plus.payment.request(channel, varpay, function(result) {
w.close();w=null;
plus.nativeUI.alert("支付成功!", function() {
saveSuccess()
});
}, function(e) {
w.close();w=null;
plus.nativeUI.alert("支付失败:" + e.message);
});
}, "json");
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
switch (xhr.readyState) {
case 4:
w.close();w=null;
if (xhr.status == 200) {
alert(xhr.result);
plus.payment.request(channel, xhr.result, function(result) {
plus.nativeUI.alert("支付成功!", function() {
saveSuccess()
});
}, function(error) {
plus.nativeUI.alert("支付失败:" + error.code);
});
} else {
alert("获取订单信息失败!");
}
break;
default:
break;
}
}
}
</script>
四,注意的细节:
1.测试包名可随意填写,格式参照(应用在一台设备上的唯一标识,在manifest文件里面声明,该包名应和正式发布应用的包名一致。例如,微信的包名为com.tencent.mm)
- 签名:如果是dcloud证书打包,包名默认为:d382d671c6672cba4b87980992cd9d77(必须小写)
- 支付测试时必须打包成.apk,才能测试。
如还不能支付,请检查参数是否正确,参数顺序是否正确,包名是否匹配,以及appid和商户号,以及支付签名是否正确有效。
本人第一次在dcloud上写文章,写的不好,请大家多多包涵,觉得有帮助,感谢送分!!!其他的不多说,本文为解决hbuilder上开发app微信支付的诸多细节,因缺少文档带来的不便。
一.开发前准备:
1.首先必须在微信开放平台注册账号,认证开发者资质。附链接:https://open.weixin.qq.com/
- 新建移动应用,如果要跟微信公众号的账号同步,可以关联上公众账号.如图附件图1.
- 新建应用的要填写的应用签名和包名(这个后面说配置)
- 要为所建应用申请微信支付,申请成功之后,获取商户号以及微信支付签名串paysignkey(32位)以备用。
二,java服务端代码:
/**
- app微信支付 调用接口
- @return
-
@throws Exception
*/
public String getWxPayShopParameters()throws Exception{
BigDecimal totalAmt = new BigDecimal (getParameter("total"));
String notify_url = getUrl()+"/appshop/app_shop_api!notifywxPayment.action"; //支付成功通知路径
Setting setting = SettingUtil.getSetting();
String appId = setting.getShopAppId();//移动应用的appid
String paySignKey = setting.getShopAppPaySignKey();//微信支付签名串
String mch_id = setting.getShopPartnerId(); //商户号(微信支付申请的商户号)
String totalfee = totalAmt.multiply(new BigDecimal(100)).intValue() + ""; // 支付金额,单位为分
String nonce_str = WxUtil.CreateNoncestr(); //随机数
String body = getParameter("body"); //商品描述
String attach = appId; //附加数据
String out_trade_no = getParameter("out_trade_no"); //商户订单号
String spbill_create_ip = getRequest().getRemoteAddr(); //订单生成的机器 IP
String trade_type = "APP";//交易类型
SortedMap<String, String> packageParams = new TreeMap<String, String>();
packageParams.put("appid", appId);
packageParams.put("mch_id", mch_id);
packageParams.put("nonce_str", nonce_str);
if(body != null && body.length() > 15) {
body = body.substring(0, 10) + "...";
}
packageParams.put("body", body);
packageParams.put("attach", attach);
packageParams.put("out_trade_no", out_trade_no);
packageParams.put("total_fee", totalfee);
packageParams.put("fee_type", "CNY");//币种
packageParams.put("spbill_create_ip", spbill_create_ip);
packageParams.put("notify_url", notify_url);
packageParams.put("trade_type", trade_type);
//packageParams.put("openid", "oc3KnjpEVsQDDYWq-KHMSPDhOTwU");String sign = WxUtil.createSign(packageParams, paySignKey); packageParams.put("sign", sign);//打包签名 String xml = WxUtil.ArrayToXml(packageParams); log.info("packageParams:" + packageParams); Map<String, Object> dataMap = new HashMap(); try { dataMap = WxUtil.getPrepayId(xml); log.info("dataMap:" + dataMap); } catch (Exception e) { e.printStackTrace(); } if(!"SUCCESS".equals(dataMap.get("return_code")) || !"SUCCESS".equals(dataMap.get("result_code"))) { throw new RuntimeException("获取prepay_id失败!"); } String prepay_id = (String) dataMap.get("prepay_id"); //wxOrderInfo.setPrepayId(prepay_id); SortedMap<String, String> finalpackage = new TreeMap<String, String>(); String timestamp = String.valueOf(System.currentTimeMillis() / 1000); String nonceStr2 = nonce_str; //需要的参数如下: finalpackage.put("appid",appId); finalpackage.put("partnerid",mch_id); finalpackage.put("prepayid", prepay_id); finalpackage.put("package", "Sign=WXPay"); finalpackage.put("noncestr",nonceStr2); finalpackage.put("timestamp",timestamp); String paySign = WxUtil.createSign(finalpackage, paySignKey); finalpackage.put("sign", paySign); return ajax(finalpackage);
}
三,hbuilder页面逻辑代码:
<script type="text/javascript">
mui.init();
var channel = null;
var channels = null;
var pays={};
function plusReady(){
// 获取支付通道
plus.payment.getChannels(function(cs) {
channels = cs;
}, function(e) {
alert("获取支付通道失败:" + e.message);
});
}
document.addEventListener('plusready',plusReady,false);
var w=null;
var WXPAYSERVER='..../gateway/mui_pay!getWxPayShopParameters.action?payid=';
var ALIPAYSERVER='.../payservice?payid='
//调用支付
function pay(id,amount,sheetNo){
if(w){return;}//检查是否请求订单中
// 从服务器请求支付订单
var PAYSERVER = '';
if (id == 'alipay') {
PAYSERVER = ALIPAYSERVER;
} else if (id == 'wxpay') {
PAYSERVER = WXPAYSERVER;
} else {
plus.nativeUI.alert("不支持此支付通道!");
return;
}
//获取支付通道
for (var i in channels) {
if (channels[i].id == id) {
channel = channels[i];
}
}
w=plus.nativeUI.showWaiting();
//获取支付通道
mui.get(PAYSERVER, {
total: 0.01,//支付费用
body: "测试支付",
out_trade_no:sheetNo
}, function(data) {
var varpay = {//参数顺序必须正确
retcode: 0,//5+必备参数
retmsg: "ok",//5+必备参数
appid: data.appid,
noncestr: data.noncestr,
package: "Sign=WXPay",
partnerid: data.partnerid,
prepayid: data.prepayid,
timestamp: data.timestamp,
sign: data.sign
}
plus.payment.request(channel, varpay, function(result) {
w.close();w=null;
plus.nativeUI.alert("支付成功!", function() {
saveSuccess()
});
}, function(e) {
w.close();w=null;
plus.nativeUI.alert("支付失败:" + e.message);
});
}, "json");
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
switch (xhr.readyState) {
case 4:
w.close();w=null;
if (xhr.status == 200) {
alert(xhr.result);
plus.payment.request(channel, xhr.result, function(result) {
plus.nativeUI.alert("支付成功!", function() {
saveSuccess()
});
}, function(error) {
plus.nativeUI.alert("支付失败:" + error.code);
});
} else {
alert("获取订单信息失败!");
}
break;
default:
break;
}
}
}
</script>
四,注意的细节:
1.测试包名可随意填写,格式参照(应用在一台设备上的唯一标识,在manifest文件里面声明,该包名应和正式发布应用的包名一致。例如,微信的包名为com.tencent.mm)
- 签名:如果是dcloud证书打包,包名默认为:d382d671c6672cba4b87980992cd9d77(必须小写)
- 支付测试时必须打包成.apk,才能测试。
如还不能支付,请检查参数是否正确,参数顺序是否正确,包名是否匹配,以及appid和商户号,以及支付签名是否正确有效。

PHP开发中的缓存技术汇总
在PHP开发中,出于对网站服务器负载的考虑,往往需要对页面、数据等内容进行缓存处理,下面就来看看,在PHP开发中有哪些缓存方式吧。
1、页面部分缓存
该种方式,是将一个页面中不经常变的部分进行静态缓存,而经常变化的块不缓存,最后组装在一起显示;可以使用类似于ob_get_contents的方式实现,也可以利用类似ESI之类的页面片段缓存策略,使其用来做动态页面中相对静态的片段部分的缓存(ESI技术,请baidu,此处不详讲)。该种方式可以用于如商城中的商品页;
2、数据缓存
顾名思义,就是缓存数据的一种方式;比如,商城中的某个商品信息,当用商品id去请求时,就会得出包括店铺信息、商品信息等数据,此时就可以将这些数据缓存到一个php文件中,文件名包含商品id来建一个唯一标示;下一次有人想查看这个商品时,首先就直接调这个文件里面的信息,而不用再去数据库查询;其实缓存文件中缓存的就是一个php数组之类;Ecmall商城系统里面就用了这种方式;
3、全页面静态化缓存
也就是将页面全部生成html静态页面,用户访问时直接访问的静态页面,而不会去走php服务器解析的流程。此种方式,在CMS系统中比较常见,比如dedecms;一种比较常用的实现方式是用输出缓存:
Ob_start()
**要运行的代码*
$content = Ob_get_contents();
**将缓存内容写入html文件*
Ob_end_clean();
4、查询缓存
其实这跟数据缓存是一个思路,就是根据查询语句来缓存;将查询得到的数据缓存在一个文件中,下次遇到相同的查询时,就直接先从这个文件里面调数据,不会再去查数据库;但此处的缓存文件名可能就需要以查询语句为基点来建立唯一标示;按时间变更进行缓存。
其实,这一条不是真正的缓存方式;上面的2、3、4的缓存技术一般都用到了时间变更判断;就是对于缓存文件您需要设一个有效时间,在这个有效时间内,相同的访问才会先取缓存文件的内容,但是超过设定的缓存时间,就需要重新从数据库中获取数据,并生产最新的缓存文件;
5、按内容变更进行缓存
这个也并非独立的缓存技术,需结合着用;就是当数据库内容被修改时,即刻更新缓存文件;
比如,一个人流量很大的商城,商品很多,商品表必然比较大,这表的压力也比较重;就可以对商品显示页进行页面缓存;当商家在后台修改这个商品的信息时,点击保存,我们同时就更新缓存文件;那么,买家访问这个商品信息时,实际上访问的是一个静态页面,而不需要再去访问数据库;试想,如果对商品页不缓存,那么每次访问一个商品就要去数据库查一次,如果有10万人在线浏览商品,那服务器压力就大了;
6、apache缓存模块
apache安装完以后,是不允许被cache的。如果外接了cache或squid服务器要求进行web加速的话,就需要在htttpd.conf里进行设置,当然前提是在安装apache的时候要激活mod_cache的模块。
安装apache时:./configure --enable-cache --enable-disk-cache --enable-mem-cache
7、php APC缓存扩展
Php有一个APC缓存扩展,windows下面为php_apc.dll,需要先加载这个模块,然后是在php.ini里面进行配置:
[apc]
extension=php_apc.dll
apc.rfc1867 = on
upload_max_filesize = 100M
post_max_size = 100M
apc.max_file_size = 200M
upload_max_filesize = 1000M
post_max_size = 1000M
max_execution_time = 600 ; 每个PHP页面运行的最大时间值(秒),默认30秒
max_input_time = 600 ; 每个PHP页面接收数据所需的最大时间,默认60
memory_limit = 128M ; 每个PHP页面所吃掉的最大内存,默认8M
比较知名的是XCache、Turck MM Cache、PHP Accelerator等
8、内存式缓存
提到这个,可能大家想到的首先就是Memcached;memcached是高性能的分布式内存缓存服务器。 一般的使用目的是,通过缓存数据库查询结果,减少数据库访问次数,以提高动态Web应用的速度、 提高可扩展性。它就是将需要缓存的信息,缓存到系统内存中,需要获取信息时,直接到内存中取;比较常用的方式就是 key-->value方式;
<?php
$memcachehost = '192.168.6.191';
$memcacheport = 11211;
$memcachelife = 60;
$memcache = new Memcache;
$memcache->connect($memcachehost,$memcacheport) or die ("Could not connect");
$memcache->set('key','缓存的内容');
$get = $memcache->get($key); //获取信息
?>
在PHP开发中,出于对网站服务器负载的考虑,往往需要对页面、数据等内容进行缓存处理,下面就来看看,在PHP开发中有哪些缓存方式吧。
1、页面部分缓存
该种方式,是将一个页面中不经常变的部分进行静态缓存,而经常变化的块不缓存,最后组装在一起显示;可以使用类似于ob_get_contents的方式实现,也可以利用类似ESI之类的页面片段缓存策略,使其用来做动态页面中相对静态的片段部分的缓存(ESI技术,请baidu,此处不详讲)。该种方式可以用于如商城中的商品页;
2、数据缓存
顾名思义,就是缓存数据的一种方式;比如,商城中的某个商品信息,当用商品id去请求时,就会得出包括店铺信息、商品信息等数据,此时就可以将这些数据缓存到一个php文件中,文件名包含商品id来建一个唯一标示;下一次有人想查看这个商品时,首先就直接调这个文件里面的信息,而不用再去数据库查询;其实缓存文件中缓存的就是一个php数组之类;Ecmall商城系统里面就用了这种方式;
3、全页面静态化缓存
也就是将页面全部生成html静态页面,用户访问时直接访问的静态页面,而不会去走php服务器解析的流程。此种方式,在CMS系统中比较常见,比如dedecms;一种比较常用的实现方式是用输出缓存:
Ob_start()
**要运行的代码*
$content = Ob_get_contents();
**将缓存内容写入html文件*
Ob_end_clean();
4、查询缓存
其实这跟数据缓存是一个思路,就是根据查询语句来缓存;将查询得到的数据缓存在一个文件中,下次遇到相同的查询时,就直接先从这个文件里面调数据,不会再去查数据库;但此处的缓存文件名可能就需要以查询语句为基点来建立唯一标示;按时间变更进行缓存。
其实,这一条不是真正的缓存方式;上面的2、3、4的缓存技术一般都用到了时间变更判断;就是对于缓存文件您需要设一个有效时间,在这个有效时间内,相同的访问才会先取缓存文件的内容,但是超过设定的缓存时间,就需要重新从数据库中获取数据,并生产最新的缓存文件;
5、按内容变更进行缓存
这个也并非独立的缓存技术,需结合着用;就是当数据库内容被修改时,即刻更新缓存文件;
比如,一个人流量很大的商城,商品很多,商品表必然比较大,这表的压力也比较重;就可以对商品显示页进行页面缓存;当商家在后台修改这个商品的信息时,点击保存,我们同时就更新缓存文件;那么,买家访问这个商品信息时,实际上访问的是一个静态页面,而不需要再去访问数据库;试想,如果对商品页不缓存,那么每次访问一个商品就要去数据库查一次,如果有10万人在线浏览商品,那服务器压力就大了;
6、apache缓存模块
apache安装完以后,是不允许被cache的。如果外接了cache或squid服务器要求进行web加速的话,就需要在htttpd.conf里进行设置,当然前提是在安装apache的时候要激活mod_cache的模块。
安装apache时:./configure --enable-cache --enable-disk-cache --enable-mem-cache
7、php APC缓存扩展
Php有一个APC缓存扩展,windows下面为php_apc.dll,需要先加载这个模块,然后是在php.ini里面进行配置:
[apc]
extension=php_apc.dll
apc.rfc1867 = on
upload_max_filesize = 100M
post_max_size = 100M
apc.max_file_size = 200M
upload_max_filesize = 1000M
post_max_size = 1000M
max_execution_time = 600 ; 每个PHP页面运行的最大时间值(秒),默认30秒
max_input_time = 600 ; 每个PHP页面接收数据所需的最大时间,默认60
memory_limit = 128M ; 每个PHP页面所吃掉的最大内存,默认8M
比较知名的是XCache、Turck MM Cache、PHP Accelerator等
8、内存式缓存
提到这个,可能大家想到的首先就是Memcached;memcached是高性能的分布式内存缓存服务器。 一般的使用目的是,通过缓存数据库查询结果,减少数据库访问次数,以提高动态Web应用的速度、 提高可扩展性。它就是将需要缓存的信息,缓存到系统内存中,需要获取信息时,直接到内存中取;比较常用的方式就是 key-->value方式;
<?php
$memcachehost = '192.168.6.191';
$memcacheport = 11211;
$memcachelife = 60;
$memcache = new Memcache;
$memcache->connect($memcachehost,$memcacheport) or die ("Could not connect");
$memcache->set('key','缓存的内容');
$get = $memcache->get($key); //获取信息
?>

HBuilder能否对平板上本地的SQLite数据库进行读写?如果不能,可否加上这项功能?
HBuilder能否对平板上本地的SQLite数据库进行读写?如果不能,可否加上这项功能?
我的邮箱:moyan_zh@163.com QQ:88579773 微信:jingtiankeji_zhou
HBuilder能否对平板上本地的SQLite数据库进行读写?如果不能,可否加上这项功能?
我的邮箱:moyan_zh@163.com QQ:88579773 微信:jingtiankeji_zhou

扁平化设计的几个要点
如今扁平化设计在Android开发中应用日渐广泛,扁平化设计依赖于清晰的层次结构和元素布局,不仅能给用户非常强烈的感觉,而且优秀的扁平化设计还能帮助用户理解产品以及交互,那么该如何做好扁平化设计?
拒绝特效
顾名思义,扁平化设计仅仅采用二维元素。所有元素都不加修饰——阴影、斜面、突起、渐变这样会带来深度变化的设计都是不应该的。从图片框到按钮,再到导航栏都干脆有力,需要极力避免羽化、阴影这样的特效。现实主义、3D、拟物化更是扁平化设计的大敌。
扁平化设计中的层次和其它的一一对应,但各个位面间没有交叉,不会明确区分背景图片、前景图片、按钮、文本、导航,等等。
使用简单元素
扁平设计中使用到很多简单的UI元素,比如按钮和图标。设计师更常用矩形、圆形、方形等简单的形状。元素独立。正角、直角、圆弧都非常常见。
UI元素应该在保持高可用性的前提下尽可能的简单,保证应用或网站直观、易用,无需引导。为了同时达到简单但直观的效果,你可以尝试为按钮填充深色,以鼓励用户点击。
记住,简单的元素并不意味着设计起来很简单,恰恰相反,扁平化设计理念的复杂度可以与任何其他设计风格相提并论。
关注色彩
色彩的使用对于扁平化设计来说非常重要。你可能已经发现了,扁平化设计的网站、应用色彩明显要更加鲜艳、明亮。此外扁平化设计的项目也拥有更多的色调。一般的网站很少会使用3种以上的色调,但是在扁平化设计中,平均会使用6-8种颜色。
扁平化设计的色调偏通常更有活力,色彩更纯。其主要、次要颜色通常都是非常大众化的颜色,然后再配以几种其它颜色。扁平化设计的另一个趋势在于复古颜色的使用,浅澄色、紫色、绿色、蓝色都极为流行。
注重排版
因为扁平化设计要求元素更简单,排版的重要性就更为突出了。字体的大小应该匹配整体设计,高度美化的字体会与极简设计原则相冲突。字形上可以应该使用粗体,文案要求精简、干练,最终保证产品在视觉上和措辞上的一致性。字体选择上可以使用简单的无衬线字体,通过字体大小和比重来区分元素。同时你也可以使用新奇的字体作为点缀,但一定要记得不能过火。排版的目的在于帮助用户理解设计。标签按钮等其它元素更注重增强易用性和交互性。
准扁平化设计
最近,越来越多的设计师开始赞同准扁平化的设计。在准扁平化设计中,基调仍然是扁平风格的,但会在设计方案中添加一种,且仅添加一种特效,无论是阴影也好、梯度也好,这种设计风格比严肃的扁平化更加灵活。
设计师们喜欢它,因为可以添加深度和纹理;用户喜欢它,因为它能有助于直观的交互。但反过来,也有设计师不喜欢它,因为“准”扁平风格是另两种风格的混合体,缺乏明确的定义,所以更难用好。
极简主义
扁平化设计生而简单,整体上趋近极简主义设计理念。设计中应该驱除任何无关元素,尽可能地仅使用简单的颜色与文本。如果一定需要视觉元素,你可以添加简单的图形。
现在,越来越多的网站开始应用扁平化设计,在Android开发中这一趋势更为明显。在小屏幕中,按钮和选项更少,也让扁平化设计如鱼得水,逐渐成为了如今的主流设计趋势,但是一个好的设计并不该拘泥于某种设计风格,而更多是注重实用性,但如果这个APP并不适合采用扁平化,那么就不应强行套用。
如今扁平化设计在Android开发中应用日渐广泛,扁平化设计依赖于清晰的层次结构和元素布局,不仅能给用户非常强烈的感觉,而且优秀的扁平化设计还能帮助用户理解产品以及交互,那么该如何做好扁平化设计?
拒绝特效
顾名思义,扁平化设计仅仅采用二维元素。所有元素都不加修饰——阴影、斜面、突起、渐变这样会带来深度变化的设计都是不应该的。从图片框到按钮,再到导航栏都干脆有力,需要极力避免羽化、阴影这样的特效。现实主义、3D、拟物化更是扁平化设计的大敌。
扁平化设计中的层次和其它的一一对应,但各个位面间没有交叉,不会明确区分背景图片、前景图片、按钮、文本、导航,等等。
使用简单元素
扁平设计中使用到很多简单的UI元素,比如按钮和图标。设计师更常用矩形、圆形、方形等简单的形状。元素独立。正角、直角、圆弧都非常常见。
UI元素应该在保持高可用性的前提下尽可能的简单,保证应用或网站直观、易用,无需引导。为了同时达到简单但直观的效果,你可以尝试为按钮填充深色,以鼓励用户点击。
记住,简单的元素并不意味着设计起来很简单,恰恰相反,扁平化设计理念的复杂度可以与任何其他设计风格相提并论。
关注色彩
色彩的使用对于扁平化设计来说非常重要。你可能已经发现了,扁平化设计的网站、应用色彩明显要更加鲜艳、明亮。此外扁平化设计的项目也拥有更多的色调。一般的网站很少会使用3种以上的色调,但是在扁平化设计中,平均会使用6-8种颜色。
扁平化设计的色调偏通常更有活力,色彩更纯。其主要、次要颜色通常都是非常大众化的颜色,然后再配以几种其它颜色。扁平化设计的另一个趋势在于复古颜色的使用,浅澄色、紫色、绿色、蓝色都极为流行。
注重排版
因为扁平化设计要求元素更简单,排版的重要性就更为突出了。字体的大小应该匹配整体设计,高度美化的字体会与极简设计原则相冲突。字形上可以应该使用粗体,文案要求精简、干练,最终保证产品在视觉上和措辞上的一致性。字体选择上可以使用简单的无衬线字体,通过字体大小和比重来区分元素。同时你也可以使用新奇的字体作为点缀,但一定要记得不能过火。排版的目的在于帮助用户理解设计。标签按钮等其它元素更注重增强易用性和交互性。
准扁平化设计
最近,越来越多的设计师开始赞同准扁平化的设计。在准扁平化设计中,基调仍然是扁平风格的,但会在设计方案中添加一种,且仅添加一种特效,无论是阴影也好、梯度也好,这种设计风格比严肃的扁平化更加灵活。
设计师们喜欢它,因为可以添加深度和纹理;用户喜欢它,因为它能有助于直观的交互。但反过来,也有设计师不喜欢它,因为“准”扁平风格是另两种风格的混合体,缺乏明确的定义,所以更难用好。
极简主义
扁平化设计生而简单,整体上趋近极简主义设计理念。设计中应该驱除任何无关元素,尽可能地仅使用简单的颜色与文本。如果一定需要视觉元素,你可以添加简单的图形。
现在,越来越多的网站开始应用扁平化设计,在Android开发中这一趋势更为明显。在小屏幕中,按钮和选项更少,也让扁平化设计如鱼得水,逐渐成为了如今的主流设计趋势,但是一个好的设计并不该拘泥于某种设计风格,而更多是注重实用性,但如果这个APP并不适合采用扁平化,那么就不应强行套用。
收起阅读 »
关于 iOS 上架时,Missing Push Notification Entitlement 的问题
不知道从何时开始,提交 App 到 App Store 上审核以后,当天会在邮箱中接受到一封标题为:iTunes Connect: Your app "XXX" (Apple ID: xxxxxxxx) has one or more issues 的邮件,内容如下:
Dear developer,
We have discovered one or more issues with your recent delivery for "XXX". Your delivery was successful, but you may wish to correct the following issues in your next delivery:
Missing Push Notification Entitlement - Your app appears to include API used to register with the Apple Push Notification service, but the app signature's entitlements do not include the "aps-environment" entitlement. If your app uses the Apple Push Notification service, make sure your App ID is enabled for Push Notification in the Provisioning Portal, and resubmit after signing your app with a Distribution provisioning profile that includes the "aps-environment" entitlement. See "Provisioning and Development" in the Local and Push Notification Programming Guide for more information. If your app does not use the Apple Push Notification service, no action is required. You may remove the API from future submissions to stop this warning. If you use a third-party framework, you may need to contact the developer for information on removing the API.
After you’ve corrected the issues, you can use Xcode or Application Loader to upload a new binary to iTunes Connect.
Regards,
The App Store team
很多开发者都会被这封邮件英文邮件弄昏头,以为自己的 App 审核被拒绝。但其实,根据苹果开发者论坛的咨询和回复:https://forums.developer.apple.com/thread/15011,这封邮件仅仅是一封警告邮件,如果 App 中并没有使用到推送功能的话,开发者可以直接忽略到这封邮件,因为它并不会影响到 App 的审核。
不知道从何时开始,提交 App 到 App Store 上审核以后,当天会在邮箱中接受到一封标题为:iTunes Connect: Your app "XXX" (Apple ID: xxxxxxxx) has one or more issues 的邮件,内容如下:
Dear developer,
We have discovered one or more issues with your recent delivery for "XXX". Your delivery was successful, but you may wish to correct the following issues in your next delivery:
Missing Push Notification Entitlement - Your app appears to include API used to register with the Apple Push Notification service, but the app signature's entitlements do not include the "aps-environment" entitlement. If your app uses the Apple Push Notification service, make sure your App ID is enabled for Push Notification in the Provisioning Portal, and resubmit after signing your app with a Distribution provisioning profile that includes the "aps-environment" entitlement. See "Provisioning and Development" in the Local and Push Notification Programming Guide for more information. If your app does not use the Apple Push Notification service, no action is required. You may remove the API from future submissions to stop this warning. If you use a third-party framework, you may need to contact the developer for information on removing the API.
After you’ve corrected the issues, you can use Xcode or Application Loader to upload a new binary to iTunes Connect.
Regards,
The App Store team
很多开发者都会被这封邮件英文邮件弄昏头,以为自己的 App 审核被拒绝。但其实,根据苹果开发者论坛的咨询和回复:https://forums.developer.apple.com/thread/15011,这封邮件仅仅是一封警告邮件,如果 App 中并没有使用到推送功能的话,开发者可以直接忽略到这封邮件,因为它并不会影响到 App 的审核。
收起阅读 »
如何选择Android模拟器?
在Android开发中,很多Android开发者都遇到如何选择一款好用的模拟器这个问题,今天就在这总结一下,关于Android模拟器该如何选择的问题。
1、Genymotion 模拟器:
优点:速度很快,比Android-SDK,基本上调试个UI足够用了,更新也比较容易,官网也容易访问,还有中文的介绍。
缺点:需要注册,免费版有功能限制,但是足够用了,需要安装配置,稍显麻烦,在Eclipse和Android Studio中使用需要单独配置,还好官网都有介绍,只不过是英文的。
2、Android-SDK 模拟器:
优点:配置简单;
缺点:卡的要死,因为国内对于Google官网访问的限制所以更新也是麻烦事,所以不推荐使用。
3、开发板或者真机:
缺点:没有Android机器的需要花钱买一个。
优点:快、真实、可以调试任何的程序,真实的反应你的程序问题。
在Android开发中,很多Android开发者都遇到如何选择一款好用的模拟器这个问题,今天就在这总结一下,关于Android模拟器该如何选择的问题。
1、Genymotion 模拟器:
优点:速度很快,比Android-SDK,基本上调试个UI足够用了,更新也比较容易,官网也容易访问,还有中文的介绍。
缺点:需要注册,免费版有功能限制,但是足够用了,需要安装配置,稍显麻烦,在Eclipse和Android Studio中使用需要单独配置,还好官网都有介绍,只不过是英文的。
2、Android-SDK 模拟器:
优点:配置简单;
缺点:卡的要死,因为国内对于Google官网访问的限制所以更新也是麻烦事,所以不推荐使用。
3、开发板或者真机:
缺点:没有Android机器的需要花钱买一个。
优点:快、真实、可以调试任何的程序,真实的反应你的程序问题。

Android开发中如何简化findViewById类型转换
写布局在Android开发中是最重要也是非常麻烦的一件事,不仅会耗费Android开发者的大量时间,而且初始化控件,写findViewById去类型转换也是非常耗时的,今天就告诉你一个小窍门,通过泛型来简化findViewById类型转换。
具体做法如下
1创建一个基类,BaseActivity并继承Activity
方法如下:
public class BaseActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
protected <T extends View> T generateFindViewById(int id) {
//return返回view时,加上泛型T
return (T) findViewById(id);
}
}
2自己写的Activity都去继承BaseActivity
之后我们自己写的每一个Activity都去继承BaseActivity,然后在初始化控件时直接使用generateFindViewById来代替findViewById即可。
这个问题,可能只存在于还在用eclipse开发,或者是使用了Android Studio之后,但是不会使用ButterKnife Zelezny 这个工具的的童鞋,学习了这个小窍门之后,你就能摆脱这样的痛苦,提高自己的开发效率。
写布局在Android开发中是最重要也是非常麻烦的一件事,不仅会耗费Android开发者的大量时间,而且初始化控件,写findViewById去类型转换也是非常耗时的,今天就告诉你一个小窍门,通过泛型来简化findViewById类型转换。
具体做法如下
1创建一个基类,BaseActivity并继承Activity
方法如下:
public class BaseActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
protected <T extends View> T generateFindViewById(int id) {
//return返回view时,加上泛型T
return (T) findViewById(id);
}
}
2自己写的Activity都去继承BaseActivity
之后我们自己写的每一个Activity都去继承BaseActivity,然后在初始化控件时直接使用generateFindViewById来代替findViewById即可。
这个问题,可能只存在于还在用eclipse开发,或者是使用了Android Studio之后,但是不会使用ButterKnife Zelezny 这个工具的的童鞋,学习了这个小窍门之后,你就能摆脱这样的痛苦,提高自己的开发效率。
收起阅读 »
Linux下开发 5+ app
公司开发环境是linux, 为了用5+ SDK, 不得不寻找HBuilder以外的方法, 同时项目中需集成第三方SDK, 有本地代码需要本地打包. 此为背景.
假设app名为foo, 不管是在线还是本地打包, 代码目录会被放存储卡的/Android/data/com.foo/apps/foo/www目录下, 所以要实现实时刷新, 只需要解决文件同步和刷新界面的问题.
1. 文件同步
有现成的工具可以使用, adb-sync, google的python脚本用于实现本地某个目录和android某个目录的同步. github地址https://github.com/google/adb-sync
我的用法: 写个小脚本每5秒同步一次
#!/bin/bash
while [ true ]; do
/bin/sleep 5
./adb-sync --delete /media/xxx/app/ /storage/emulated/0/Android/data/com.foo/apps/foo/www/
done
2. 打开5+ runtime的webview调试
本地打包会把chrome调试关闭. 可以在首页加入以下代码:
mui.plusReady(function(){
var webView = plus.android.importClass("android.webkit.WebView");
webView.setWebContentsDebuggingEnabled(true);
});
这样本地打包的也可以用chrome调试了, PS: chrome调试参考http://ask.dcloud.net.cn/article/69
3. webview自动刷新
目前没有找到好的方法, 在chrome调试时手动F5刷新就好了
结论
最终的流程是: 找个顺手的IDE, 编辑代码 -> 保存 -> 切换到chrome -> F5刷新看效果
比不上windows下HBuilder的爽快, 但至少可以在linux下比较快的码代码了, 嗯
公司开发环境是linux, 为了用5+ SDK, 不得不寻找HBuilder以外的方法, 同时项目中需集成第三方SDK, 有本地代码需要本地打包. 此为背景.
假设app名为foo, 不管是在线还是本地打包, 代码目录会被放存储卡的/Android/data/com.foo/apps/foo/www目录下, 所以要实现实时刷新, 只需要解决文件同步和刷新界面的问题.
1. 文件同步
有现成的工具可以使用, adb-sync, google的python脚本用于实现本地某个目录和android某个目录的同步. github地址https://github.com/google/adb-sync
我的用法: 写个小脚本每5秒同步一次
#!/bin/bash
while [ true ]; do
/bin/sleep 5
./adb-sync --delete /media/xxx/app/ /storage/emulated/0/Android/data/com.foo/apps/foo/www/
done
2. 打开5+ runtime的webview调试
本地打包会把chrome调试关闭. 可以在首页加入以下代码:
mui.plusReady(function(){
var webView = plus.android.importClass("android.webkit.WebView");
webView.setWebContentsDebuggingEnabled(true);
});
这样本地打包的也可以用chrome调试了, PS: chrome调试参考http://ask.dcloud.net.cn/article/69
3. webview自动刷新
目前没有找到好的方法, 在chrome调试时手动F5刷新就好了
结论
最终的流程是: 找个顺手的IDE, 编辑代码 -> 保存 -> 切换到chrome -> F5刷新看效果
比不上windows下HBuilder的爽快, 但至少可以在linux下比较快的码代码了, 嗯
收起阅读 »
Swift那些鲜为人知的特性
在iOS开发中,Swift语言有各种各样缺乏文档记录的特性,这些鲜为人知的特性放在那里,等着我们去发现去使用,现在就让我们看看有哪些特性吧
@transparent
该特性会导致编译器在管道(pipeline)中更早地将函数内联。它用于“像+(Int, Int)这样非常原始的函数”,而“不应该用于独立函数”。
甚至在没有优化设置的调试模式下,@transparent特性函数就会被内联,所以在调用“1+1”这样的函数时候并不会特别慢,另外这个特性与@inline(__always)非常类似。
@availability
这个特性可以用来标识某些函数只在某些平台或版本上可用。第一个参数是平台,可以用星号(*)代表一切可用,还可以是iOS或OS X。因为如果需要针对不同的平台,就要指定多个@availability属性。
如果需要表示该函数在某个给定的平台完全不可用时,可以将第二个参数置为unavailable。此外,还可以用introduced,deprecated和obsoleted来指定一个或是多个版本的组合:obsoleted意味着该项已经删除,deprecated仅仅表示如果使用就会给予警告。最后可以设置message的值,如果该项被使用了就由编译器输出。如果调用另一个被标志为@noreturn的函数,那么编译器会忽略掉当前函数中缺失的返回值(missing return values),因为编译器理解程序的控制流。
@inline
这个特性为编译器提供了内联提示。有效的取值是always和never。除非认为必须要用这两个值,否则就不会使用它(特别是always)。到目前为止与其相关的规则还不是很明确,在有限的测试下,它可以正常地工作,但还要视具体情况而定。
进一步的解释:尽管底层虚拟机(Low Level Virtual Machine, LLVM)有强制内联的概念,但目前还不知道这个@inline特性是否与其直接映射,也不知道是否存在大小方面的限制,但这将会导致编译器忽略这一点而跳过内联。理论上说应该是这样的,但我不保证一定是。
注意(当优化设置关闭时)在调试模式下的构建将忽略@inline。
@asmname
该属性给出了函数、方法或属性实现的符号名称。如果已经知道对应的函数参数及其类型,那么就可以直接调用Swift的内部标准库函数,甚至不用头文件,也可以方便地调用C语言编写的函数:@asmname("function") func f()
@semantics
这又是另一个谜。参数看起来像是array.mutate_unknown或array.init这样的字符串数组。想必这是要告诉编译器(或静态分析器)函数是如何工作的。
@unsafe_no_objc_tagged_pointer
上面这个仍然是个谜,但据猜测,它是在告诉Swift与Objective-C联系的时候不要使用tagged pointer。
在iOS开发中,Swift语言有各种各样缺乏文档记录的特性,这些鲜为人知的特性放在那里,等着我们去发现去使用,现在就让我们看看有哪些特性吧
@transparent
该特性会导致编译器在管道(pipeline)中更早地将函数内联。它用于“像+(Int, Int)这样非常原始的函数”,而“不应该用于独立函数”。
甚至在没有优化设置的调试模式下,@transparent特性函数就会被内联,所以在调用“1+1”这样的函数时候并不会特别慢,另外这个特性与@inline(__always)非常类似。
@availability
这个特性可以用来标识某些函数只在某些平台或版本上可用。第一个参数是平台,可以用星号(*)代表一切可用,还可以是iOS或OS X。因为如果需要针对不同的平台,就要指定多个@availability属性。
如果需要表示该函数在某个给定的平台完全不可用时,可以将第二个参数置为unavailable。此外,还可以用introduced,deprecated和obsoleted来指定一个或是多个版本的组合:obsoleted意味着该项已经删除,deprecated仅仅表示如果使用就会给予警告。最后可以设置message的值,如果该项被使用了就由编译器输出。如果调用另一个被标志为@noreturn的函数,那么编译器会忽略掉当前函数中缺失的返回值(missing return values),因为编译器理解程序的控制流。
@inline
这个特性为编译器提供了内联提示。有效的取值是always和never。除非认为必须要用这两个值,否则就不会使用它(特别是always)。到目前为止与其相关的规则还不是很明确,在有限的测试下,它可以正常地工作,但还要视具体情况而定。
进一步的解释:尽管底层虚拟机(Low Level Virtual Machine, LLVM)有强制内联的概念,但目前还不知道这个@inline特性是否与其直接映射,也不知道是否存在大小方面的限制,但这将会导致编译器忽略这一点而跳过内联。理论上说应该是这样的,但我不保证一定是。
注意(当优化设置关闭时)在调试模式下的构建将忽略@inline。
@asmname
该属性给出了函数、方法或属性实现的符号名称。如果已经知道对应的函数参数及其类型,那么就可以直接调用Swift的内部标准库函数,甚至不用头文件,也可以方便地调用C语言编写的函数:@asmname("function") func f()
@semantics
这又是另一个谜。参数看起来像是array.mutate_unknown或array.init这样的字符串数组。想必这是要告诉编译器(或静态分析器)函数是如何工作的。
@unsafe_no_objc_tagged_pointer
上面这个仍然是个谜,但据猜测,它是在告诉Swift与Objective-C联系的时候不要使用tagged pointer。

团队承接hbuilder,h5+,mui的外包
如题:有需要外包的请联系我,前端,后台都可以全包,QQ1046373779
如题:有需要外包的请联系我,前端,后台都可以全包,QQ1046373779