在线看电影等a^x a^y = a^x ...

ACM_HDU(26)
ACM_数论and数学类(54)
求模方程 a^x = b(mod n)是否存在解x,如果存在,输出最小的x。
解题思路:
首先考虑简单的情况,求a^x = b(mod n),如果a,n互质,由欧拉定理 a^( phi(n) ) = 1 (mod n)可知,当x&phi(n)后a^x就开始循环了。所以只需要检查前phi(n)项是否有解,因为phi(n) &= n,为了方便,统一设定检查范围为0到n。然后我们先检查前m项 (令m = sqrt(n) ),保存所有a^i mod n的值 (0 &= i & m),接下来对于a^(m),a^(m+1)...a^(2m+1)就不用枚举来检查了,如果他们当中有解,则相当于存在a^i*
a^m = b(mod n)。两边左乘a^(-m)得 a^i = ( b*a^(-m) ) (mod n),所以只需要判断有没有a^i = b*a^(-m) 。
如果a,n不互质的话,直接这样子做就不行了,既然我们有了a,n互质的做法,那就要想办法使得a,n互质。
所以每次都要把a,n的gcd约去,同时b也要约去gcd,如果b不能约去gcd说明无解。这样假设需要cnt个a和n约去才能使得a,n互质,这cnt个a约后得到的设为now,结果就是求now*a^x = b (mod n),也就转化成a,n互质的情况了,这样就很简单了~贴个代码 (ps:貌似好久没写博客了)
#include &stdio.h&
#include &math.h&
#include &map&
#define LL __int64
int exgcd(int a, int b, int &x, int &y) {
x = 1; y = 0;
int ret = exgcd(b, a%b, y, x);
y -= a/b*x;
int gcd(int a, int b) {
return b ? gcd(b, a%b) :
int inv(int a, int n) {
int d = exgcd(a, n, x, y);
int mul_mod(LL a, LL b, int n) {
return a * b %
int pow_mod(int x, int n, int m) {
int ret = 1;
while(n) {
if(n&1) ret = (LL)ret*x%m;
x = (LL)x*x%m;
//求解a^x = b (mod n) a, n互质
int log_mod(int a, int b, int n) {
int m = sqrt(n+0.5);
int v = inv(pow_mod(a, m, n), n);
map&int,int&
int e = 1;
for(int i = 1;i & i++) {
e = mul_mod(e, a, n);
if(!x.count(e)) x[e] =
for(int i = 0;i & i++) {
if(x.count(b))
return i*m + x[b];
b = mul_mod(b, v, n);
return -1;
int solve(int a, int p, int b) {
int cnt = 0;
int now = 1;
while(true) {
// 结果已经等于b的情况
if(now%p == b)
int d = gcd(a, p);
if(d == 1) {
int v = inv(now, p);
int ret = log_mod(a, (LL)b*v%p, p);
if(ret == -1)
return -1;
return ret +
return -1;
now = (LL)now*(a/d)%p;
cnt++;
int main() {
while(scanf(&%d%d%d&, &a, &p, &b) != -1) {
if(b &= p) {
puts(&Orz,I can’t find D!&);
int ans = solve(a, p, b);
if(ans == -1)
puts(&Orz,I can’t find D!&);
printf(&%d\n&, ans);
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:132545次
积分:2869
积分:2869
排名:第9965名
原创:147篇
评论:109条
(1)(6)(3)(2)(7)(7)(5)(8)(16)(17)(10)(21)(32)(18)(1)分享iOS开发技术经验的自媒体网站
一、什么是NSRunLoop
NSRunLoop是消息机制的处理模式
NSRunLoop的作用在于有事情做的时候使的当前NSRunLoop的线程工作,没有事情做让当前NSRunLoop的线程休眠
NSTimer默认添加到当前NSRunLoop中,也可以手动制定添加到自己新建的NSRunLoop
NSRunLoop就是一直在循环检测,从线程start到线程end,检测inputsource(如点击,双击等操作)同步事件,检测timesource同步事件,检测到输入源会执行处理函数,首先会产生通知,corefunction向线程添加runloop observers来监听事件,意在监听事件发生时来做处理。
在单线程的app中,不需要注意Run Loop,但不代表没有。程序启动时,系统已经在主线程中加入了Run Loop。它保证了我们的主线程在运行起来后,就处于一种“等待”的状态(而不像一些命令行程序一样运行一次就结束了),这个时候如果有接收到的事件(Timer的定时到了或是其他线程的消息),就会执行任务,否则就处于休眠状态。
runloopmode是一个集合,包括监听:事件源,定时器,以及需通知的runloop observers
模式包括:
default模式:几乎包括所有输入源(除NSConnection) NSDefaultRunLoopMode模式
mode模式:处理modal panels
connection模式:处理NSConnection事件,属于系统内部,用户基本不用
event tracking模式:如组件拖动输入源 UITrackingRunLoopModes 不处理定时事件
common modes模式:NSRunLoopCommonModes 这是一组可配置的通用模式。将input sources与该模式关联则同时也将input sources与该组中的其它模式进行了关联。
App Thinning 是苹果在去年 WWDC, 也就是 iOS 9 中推出的为 App 瘦身的一个新的技术。 App Thinning 主要分为 3 个部分:
App Slicing
On Demand Resources
App Slicing
我们正常的应用中都会用到图片资源,为了适配 iPhone 6 Plus 以及 iPhone 6, 图片资源需要包含 @2x 的图片 和 @3x 的图片,而 Slicing 就是在这一步进行优化,Slicing 会根据用户在 App Store 下载的不同设备选择对应的资源。例如:当用户使用 iPhone 6 在 App Store 上下载 App 的时候,App Store 只会给予他 @2x 的图片,而不会像以前一样,不管三七二十一我把所有的资源都给你,根据苹果的描述,这大约能节约你 30% 到 50% 的大小。而你要做的事情,仅仅是使用 Xcode 7 IDE, 并且使用其中的 Assert Catalog 管理你的资源文件。
不过 Slicing 因为 iCloud 备份的问题, 知道 iOS 9.0.2 以及 Xcode 7.0.1 才可以被使用
Bitcode 是苹果在你 App 被下载之前做的另外一件优化。Bitcode 是你的代码编译为最终可执行文件的中间的一层,当你的 App 以 Bitcode 的形式提交到 iTunes Connect 的时候,iTunes Connect 会自动为合适的机器编译出对应的代码,例如:对于 64 位机器的 iPhone 6 或者 iPad Air 2,Bitcode 会为其编译出适合 64 位机器可执行文件。
对于 iOS app 来说, Bitcode 不是必须的,但 Bitcode 编译选项为 Yes(这里应该只是一个过渡期,有些第三方库如果不在继续维护了需要尽快换掉), 对于 tvOS 和 watchOS 的 app,Bitcode 的的选项必须为 Yes。
google搜索“iOS视频变下边播”,有好几篇博客写到了实现方法,其实只有一篇,其他都是copy的,不过他们都是使用的本地代理服务器的方式,原理很简单,但是缺点也很明显,需要自己写一个本地代理服务器或者使用第三方库httpSever。如果使用httpSever作为本地代理服务器,如果只缓存一个视频是没有问题的,如果缓存多个视频互相切换,本地代理服务器提供的数据很不稳定,crash概率非常大。
这里我采用ios7以后系统自带的方法实现视频边下边播,这里的边下边播不是单独开一个子线程去下载,而是把视频播放的数据给保存到本地。简而言之,就是使用一遍的流量,既播放了视频,也保存了视频。
用到的框架:&AVFoundation/AVFoundation.h&
用到的播放器:AVplayer
先说一下avplayer自身的播放原理,当我们给播放器设置好url等一些参数后,播放器就会向url所在的服务器发送请求(请求参数有两个值,一个是offset偏移量,另一个是length长度,其实就相当于NSRange一样),服务器就根据range参数给播放器返回数据。这就是大致的原理,当然实际的过程还是略微比较复杂。
下面进入主题
产品需求:
支持正常播放器的一切功能,包括暂停、播放和拖拽
如果视频加载完成且完整,将视频文件保存到本地cache,下一次播放本地cache中的视频,不再请求网络数据
如果视频没有加载完(半路关闭或者拖拽)就不用保存到本地cache
需要在视频播放器和服务器之间添加一层类似代理的机制,视频播放器不再直接访问服务器,而是访问代理对象,代理对象去访问服务器获得数据,之后返回给视频播放器,同时代理对象根据一定的策略缓存数据。
AVURLAsset中的resourceLoader可以实现这个机制,resourceLoader的delegate就是上述的代理对象。
视频播放器在开始播放之前首先检测是本地cache中是否有此视频,如果没有才通过代理获得数据,如果有,则直接播放本地cache中的视频即可。
视频播放器需要实现的功能
有开始暂停按钮
显示播放进度及总时长
可以通过拖拽从任意位置开始播放视频
视频加载中的过程和加载失败需要有相应的提示
代理对象需要实现的功能
接收视频播放器的请求,并根据请求的range向服务器请求本地没有获得的数据
缓存向服务器请求回的数据到本地
如果向服务器的请求出现错误,需要通知给视频播放器,以便视频播放器对用户进行提示
具体流程图
视频播放器处理流程
当开始播放视频时,通过视频url判断本地cache中是否已经缓存当前视频,如果有,则直接播放本地cache中视频
如果本地cache中没有视频,则视频播放器向代理请求数据
加载视频时展示正在加载的提示(菊花转)
如果可以正常播放视频,则去掉加载提示,播放视频,如果加载失败,去掉加载提示并显示失败提示
在播放过程中如果由于网络过慢或拖拽原因导致没有播放数据时,要展示加载提示,跳转到第4步
代理对象处理流程
当视频播放器向代理请求dataRequest时,判断代理是否已经向服务器发起了请求,如果没有,则发起下载整个视频文件的请求
如果代理已经和服务器建立链接,则判断当前的dataRequest请求的offset是否大于当前已经缓存的文件的offset,如果大于则取消当前与服务器的请求,并从offset开始到文件尾向服务器发起请求(此时应该是由于播放器向后拖拽,并且超过了已缓存的数据时才会出现)
如果当前的dataRequest请求的offset小于已经缓存的文件的offset,同时大于代理向服务器请求的range的offset,说明有一部分已经缓存的数据可以传给播放器,则将这部分数据返回给播放器(此时应该是由于播放器向前拖拽,请求的数据已经缓存过才会出现)
如果当前的dataRequest请求的offset小于代理向服务器请求的range的offset,则取消当前与服务器的请求,并从offset开始到文件尾向服务器发起请求(此时应该是由于播放器向前拖拽,并且超过了已缓存的数据时才会出现)
只要代理重新向服务器发起请求,就会导致缓存的数据不连续,则加载结束后不用将缓存的数据放入本地cache
如果代理和服务器的链接超时,重试一次,如果还是错误则通知播放器网络错误
如果服务器返回其他错误,则代理通知播放器网络错误
resourceLoader的难点处理
- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest
[self.pendingRequests addObject:loadingRequest];
[self dealWithLoadingRequest:loadingRequest];
return YES;
播放器发出的数据请求从这里开始,我们保存从这里发出的所有请求存放到数组,自己来处理这些请求,当一个请求完成后,对请求发出finishLoading消息,并从数组中移除。正常状态下,当播放器发出下一个请求的时候,会把上一个请求给finish。
下面这个方法发出的请求说明播放器自己关闭了这个请求,我们不需要再对这个请求进行处理,系统每次结束一个旧的请求,便必然会发出一个或多个新的请求,除了播放器已经获得整个视频完整的数据,这时候就不会再发起请求。
- (void)resourceLoader:(AVAssetResourceLoader *)resourceLoader didCancelLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest
[self.pendingRequests removeObject:loadingRequest];
下面这个方法是对播放器发出的请求进行填充数据
- (BOOL)respondWithDataForRequest:(AVAssetResourceLoadingDataRequest *)dataRequest
long long startOffset = dataRequest.requestedO
if (dataRequest.currentOffset != 0) {
startOffset = dataRequest.currentO
if ((self.task.offset +self.task.downLoadingOffset) & startOffset)
//NSLog(@"NO DATA FOR REQUEST");
return NO;
if (startOffset & self.task.offset) {
return NO;
NSData *filedata = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:_videoPath] options:NSDataReadingMappedIfSafe error:nil];
// This is the total data we have from startOffset to whatever has been downloaded so far
NSUInteger unreadBytes = self.task.downLoadingOffset - ((NSInteger)startOffset - self.task.offset);
// Respond with whatever is available if we can't satisfy the request fully yet
NSUInteger numberOfBytesToRespondWith = MIN((NSUInteger)dataRequest.requestedLength, unreadBytes);
[dataRequest respondWithData:[filedata subdataWithRange:NSMakeRange((NSUInteger)startOffset- self.task.offset, (NSUInteger)numberOfBytesToRespondWith)]];
long long endOffset = startOffset + dataRequest.requestedL
BOOL didRespondFully = (self.task.offset + self.task.downLoadingOffset) &= endO
return didRespondF
这是对存放所有的请求的数组进行处理
- (void)processPendingRequests
NSMutableArray *requestsCompleted = [NSMutableArray array];
//请求完成的数组
//每次下载一块数据都是一次请求,把这些请求放到数组,遍历数组
for (AVAssetResourceLoadingRequest *loadingRequest in self.pendingRequests)
[self fillInContentInformation:loadingRequest.contentInformationRequest]; //对每次请求加上长度,文件类型等信息
BOOL didRespondCompletely = [self respondWithDataForRequest:loadingRequest.dataRequest]; //判断此次请求的数据是否处理完全
if (didRespondCompletely) {
[requestsCompleted addObject:loadingRequest];
//如果完整,把此次请求放进 请求完成的数组
[loadingRequest finishLoading];
[self.pendingRequests removeObjectsInArray:requestsCompleted];
//在所有请求的数组中移除已经完成的
resourceLoader的难点基本上就是上面这点了,说到播放器,下面便顺便讲下AVPlayer的难点。
难点:对播放器状态的捕获
举个简单的例子,视频总长度60分,现在缓冲的数据才10分钟,然后拖动到20分钟的位置进行播放,在网速较慢的时候,视频从当前位置开始播放,必然会出现一段时间的卡顿,为了有一个更好的用户体验,在卡顿的时候,我们需要加一个菊花转的状态,现在问题就来了。
在拖动到未缓冲区域内,是否需要加菊花转,如果加,要显示多久再消失,而且如果在网速很慢的时候,播放器如果等了太久,哪怕最后有数据了,播放器也已经“死”了,它自己无法恢复播放,这个时候需要我们人为的去恢复播放,如果恢复播放不成功,那么过一段时间需要再次恢复播放,是否恢复播放成功,这里也需要捕获其状态。所以,如果要有一个好的用户体验,我们需要时时知道播放器的状态。
有两个状态需要捕获,一个是正在缓冲,一个是正在播放,监听播放的“playbackBufferEmpty”属性就可以捕获正在缓冲状态,播放器的时间监听器则可以捕获正在播放状态,我的demo中一共有4个状态:
typedef NS_ENUM(NSInteger, TBPlayerState) {
TBPlayerStateBuffering = 1,
TBPlayerStatePlaying
TBPlayerStateStopped
TBPlayerStatePause
这样可以对播放器更好的把握和处理了。然后说一说在缓冲时候的处理,以及缓冲后多久去播放,处理方法:进入缓冲状态后,缓冲2秒后去手动播放,如果播放不成功(缓冲的数据太少,还不足以播放),那就再缓冲2秒再次播放,如此循环,看详细代码:
- (void)bufferingSomeSecond
// playbackBufferEmpty会反复进入,因此在bufferingOneSecond延时播放执行完之前再调用bufferingSomeSecond都忽略
static BOOL isBuffering = NO;
if (isBuffering) {
isBuffering = YES;
// 需要先暂停一小会之后再播放,否则网络状况不好的时候时间在走,声音播放不出来
[self.player pause];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 如果此时用户已经暂停了,则不再需要开启播放了
if (self.isPauseByUser) {
isBuffering = NO;
[self.player play];
// 如果执行了play还是没有播放则说明还没有缓存好,则再次缓存一段时间
isBuffering = NO;
if (!self.currentPlayerItem.isPlaybackLikelyToKeepUp) {
[self bufferingSomeSecond];
这个demo花了我很长的时间,实现这个demo我也遇到了很多坑最后才完成的,现在我奉献出来,也许对你会有所帮助。如果你觉得不错,还请为我Star一个,也算是对我的支持和鼓励。
demo下载地址
/suifengqjn/TBPlayer
文/夜千寻墨(简书作者)
来自:/p/990ee3db0563
阿里云iOS客户端2.1.0版本中开始尝试使用Swift来写新的业务,磕磕绊绊总算是发布了新版,总结一下开发过程中得到的经验和踩过的坑吧。
使用Swift作为主要的开发语言,很难避免引入Swift编写的库。2.1.0版本引入了SwiftyJSON和Charts这两个Swift写的库,分别用于处理JSON数据和画监控图。
苹果要求使用Swift写的库,必须通过动态链接库引入,其实这一点我也是不太理解的,因为静态库也是可以依赖动态库的符号的,不存在导入多个Swift动态库的问题。允许App使用自带的动态库从iOS8才开始支持,因此必须将App支持的iOS版本升到iOS8。阿里云iOS客户端iOS7的用户不到4%,所以放弃了对iOS7的支持。
Cocoapods支持将依赖的组件编译成动态库,只需要在Podfile顶部加上”use_frameworks!&。开启这个选项之后,所有以源码引入的pod都会编译成动态链接库,而以fake framework引入的pod仍然会编译到主App里面。动态库都放在App里面的Frameworks目录,可以看到Swift相关的动态库也都拷贝进来了,所以支持Swift会导致包变大。我没有记下2.0.0版本的大小,导致没法对比2.1.0放大了多少,这是一个失误。
[~/Library/Developer/Xcode/Archives//CloudConsoleApp 15-12-17 下午9.24.xcarchive/Products/Applications/CloudConsoleApp.app/Frameworks]$ tree
├── Charts.framework
├── Charts
├── Info.plist
└── _CodeSignature
└── CodeResources
├── EAIntroView.framework
├── EAIntroView
├── Info.plist
└── _CodeSignature
└── CodeResources
├── FMDB.framework
├── FMDB
├── Info.plist
└── _CodeSignature
└── CodeResources
├── FTCoreText.framework
├── FTCoreText
├── Info.plist
└── _CodeSignature
└── CodeResources
├── JSBadgeView.framework
├── Info.plist
├── JSBadgeView
├── JSBadgeView.bundle
└── _CodeSignature
└── CodeResources
├── MBProgressHUD.framework
├── Info.plist
├── MBProgressHUD
└── _CodeSignature
└── CodeResources
├── MFSideMenu.framework
├── Info.plist
├── MFSideMenu
└── _CodeSignature
└── CodeResources
├── PFormanceKit.framework
├── Info.plist
├── PFormanceKit
└── _CodeSignature
└── CodeResources
├── Reachability.framework
├── Info.plist
├── Reachability
└── _CodeSignature
└── CodeResources
├── RegexKitLite.framework
├── Info.plist
├── RegexKitLite
└── _CodeSignature
└── CodeResources
├── SSZipArchive.framework
├── Info.plist
├── SSZipArchive
└── _CodeSignature
└── CodeResources
├── SnapKit.framework
├── Info.plist
├── SnapKit
└── _CodeSignature
└── CodeResources
├── SwiftyJSON.framework
├── Info.plist
├── SwiftyJSON
└── _CodeSignature
└── CodeResources
├── libswiftContacts.dylib
├── libswiftCore.dylib
├── libswiftCoreData.dylib
├── libswiftCoreGraphics.dylib
├── libswiftCoreImage.dylib
├── libswiftDarwin.dylib
├── libswiftDispatch.dylib
├── libswiftFoundation.dylib
├── libswiftObjectiveC.dylib
└── libswiftUIKit.dylib
27 directories, 49 files
$ file Charts
Charts: Mach-O universal binary with 2 architectures
Charts (for architecture armv7):
Mach-O dynamically linked shared library arm
Charts (for architecture arm64):
Mach-O 64-bit dynamically linked shared library
因为fake framework和源代码pod分别会编译成静态库和动态库,这样会导致一个问题,就是如果源码pod又依赖fake framework,那就没办法了。CocoaPods发现这种情况会提示下面这个错误。
target has transitive dependencies that include static binaries: (xxx.framework, xxx.framework)
pod install时会把静态库编译到App里面,源码编译成的动态库没法依赖它。最终的解决方案只能是CocoaPods对fake framework和源码pod一视同仁,都编译成动态库,这样彼此才能依赖。不知道CocoaPods什么时候会支持这样。
Swift使用Objective-C
这种情况占绝大多数。只需要在CloudConsoleApp-Bridging-Header.h这个头文件中包含相关的头文件就行。pod组件另外一种引入的方式是通过@import引入。比如SDWebImage可以通过下面两种方式引入。
//在Bridging头文件包含下面这个头文件
#import &SDWebImage/UIImageView+WebCache.h&
//另外一种办法,在Swift文件中引入。
import SDWebImage
Objective-C写的类和方法都会被改成Swift的使用方式,下面是两个很典型的例子。使用的时候需要尝试一下才能找到翻译的Swift方法。
//Objective-C
titleLabel.lineBreakMode = NSLineBreakByWordW
titleLabel.numberOfLines = 0;
cell.nameLabel?.lineBreakMode = .ByWordWrapping //全写是 NSLineBreakMode.ByWordWrapping
cell.nameLabel?.numberOfLines = 0
//Objective-C
UIImage *image = [UIImage imageNamed:@"abc"];
let image = UIImage(named: "abc")
Objective-C使用Swift
Xcode会生成一个虚拟的头文件CloudConsoleApp-Swift.h,在工程里面是找不到这个头文件的,但是可以包含,并且跳转进去。这个文件里面包含了所有从Swift导出来的符号,比如下面这个view controller就是用Swift写的。可以看出来Objectivew-C看到的名称跟Swift源码里面的名称是一样的,但是Swift会对类做demangling,变成了_TtC15CloudConsoleApp31YWSResourceDetailViewController这样的,跟C++有点类似。
SWIFT_CLASS("_TtC15CloudConsoleApp31YWSResourceDetailViewController")
@interface YWSResourceDetailViewController : UIPageViewController
@property (nonatomic, strong) NSArray * __
@property (nonatomic, copy) NSString * __null_unspecified pluginId;
@property (nonatomic, strong) YWSSegmentedControl * __nonnull segmentedC
@property (nonatomic, strong) YWSInstanceListViewController * __nonnull instanceListViewC
@property (nonatomic, strong) YWSMetricConcernedViewController * __nonnull metricConcernedViewC
@property (nonatomic, weak) IBOutlet UIBarButtonItem * __null_unspecified addMetricBarB
- (void)viewDidL
- (void)initSegmentedC
- (void)indexChanged:(id __nonnull)
- (void)onNavigationBack:(id __nonnull)
- (void)prepareForSegue:(UIStoryboardSegue * __nonnull)segue sender:(id __nullable)
- (nonnull instancetype)initWithTransitionStyle:(UIPageViewControllerTransitionStyle)style navigationOrientation:(UIPageViewControllerNavigationOrientation)navigationOrientation options:(NSDictionary&NSString *, id& * __nullable)options OBJC_DESIGNATED_INITIALIZER;
- (nullable instancetype)initWithCoder:(NSCoder * __nonnull)coder OBJC_DESIGNATED_INITIALIZER;
Swift的优缺点
这个项目刚起步,用Swift的经验尚浅,所以都是一些比较浅薄的理解,后面有更深刻的理解再补上。
代码简洁。类的声明和实现在一个文件中。
统一对属性和方法的调用,都用.。
如果不加额外的访问控制,所有的符号都是整个项目可见,无需考虑头文件的问题。
字符串处理太方便了。
//字符串比较和拼接实在是太方便了
let foo = &abc&
let bar = &abc&
if foo == bar {
//blablabla
print(&====(foo)+(bar)&)
语言上支持延迟加载。
lazy var imageView : UIImageView = {
var imageView = UIImageView(image: UIImage(named: &empty_hint&))
imageView.contentMode = .ScaleAspectFit
return imageView
lazy var infoLabel : UILabel = {
var infoLabel = UILabel()
infoLabel.lineBreakMode = .ByWordWrapping //支持换行
infoLabel.numberOfLines = 0
return infoLabel
lazy var button : UIButton = {
var button = UIButton()
button.titleLabel?.font = UIFont.systemFontOfSize(15)
button.setTitleColor(UIColor.darkGrayColor(), forState: .Normal)
button.setBackgroundImage(UIImage(named: &buy_instance_hint_button&), forState: .Normal)
button.hidden = true
return button
多返回值。比如下面这个函数,如果使用Objective-C写还是比较麻烦的。
//将 &创建中&#FA8C35& 翻译成对应的 &(字符串对象, 颜色对象)&
func YWSTranslateRichText (str : String) -> (text : String, color : UIColor) {
let statusArray = ponentsSeparatedByString(&&&)
if statusArray.count == 0 {
return ("", UIColor.lightGrayColor())
if statusArray.count == 1 {
return (statusArray[0], UIColor.lightGrayColor())
return (statusArray[0], UIColor.fromHexString(statusArray[1]))
//使用方式如下
let (text, color) = YWSTranslateRichText(instanceStatusConf)
支持字符串作为枚举值。
enum YWSECSInstanceStatus : String {
case Starting = &Starting&
case Running = &Running&
case Stopping = &Stopping&
case Stopped = &Stopped&
//使用方法
cell.ECSInstanceStatus = YWSECSInstanceStatus(rawValue: instanceStatus!)
//转换成字符串
textDetailLabel.text = YWSECSInstanceStatus.Starting.rawValue
selector类型实现了 StringLiteralConvertible,使用起来更加简单。
self.button.addTarget(self, action: &introduceResources:&, forControlEvents: .TouchUpInside)
不再需要引入libextobjc这个Pod,因为Swift支持更方便的用法。在block开始的时候,在数组里面weak所有要用到的对象。
inputViewController.finishBlock = { [weak inputViewController, weak cell, weak self] () -> Void in
函数支持默认参数。比如下面这个函数,有五个参数,其中三个有默认参数,用户需要设置的参数只有两个。
convenience init(text: String, textColor: UIColor = UIColor.whiteColor(), bgColor: UIColor, font: UIFont = UIFont.systemFontOfSize(10), inset: UIEdgeInsets = UIEdgeInsetsMake(0, 3, 0, 3)) {
lazy var vipLabel : YWSInsetsTextLabel! = YWSInsetsTextLabel(text: &vip&, bgColor: UIColor.orangeColor())
通过减少动态性,使用vtable替换原有的objc_msgSend,获取更高的性能。新增了final、private等关键字,编译器可以对代码做更多优化,提升性能并减少内存的使用。比如final方法不用放入虚表中,节省内存;跳转时不用查表,性能更佳;private的类如果发现有方法只在本文件中使用,可以直接内联,提高性能。
在Playground工程里面练习Swift编程非常之方便,尤其是测试VFL语句的时候。
Optional让人头疼,大量的?和!,没处理好很容易导致崩溃。
强类型和Optional,给JSON解释带来了灾难。
目前Xcode不支持对Swift写的代码做重构。
Build Settings里面设置Treat Warnings as Errors对Swift代码无效。
用private修饰的类,如果使用KVC来给属性设置值,编译不会报错,运行时也不会报错,但就是设置不上。去掉private就好了。
手解crash可以看到具体崩溃代码的行号。
$ symbolicatecrash ~/Downloads/034dc058c5d4ff1f717ec7a05d4d55b8 CloudConsoleApp.app.dSYM
Exception Type:
Exception Codes: #0 at 0x
Crashed Thread:
Thread 0 Crashed:
CloudConsoleApp
0xc09b4 YWSInstanceListViewController.goToBuyPage() -& () (YWSInstanceListViewController.swift:701)
CloudConsoleApp
0xc92cc specialized YWSInstanceListViewController.introduceResources(AnyObject) -& () (YWSInstanceListViewController.swift:689)
CloudConsoleApp
0xc029c @objc YWSInstanceListViewController.introduceResources(AnyObject) -& () (YWSInstanceListViewController.swift:0)
0xbe50 0x185fd0000 + 310864
0xbdcc 0x185fd0000 + 310732
0x3a88 0x185fd0000 + 211592
0xb6e4 0x185fd0000 + 308964
0xb314 0x185fd0000 + 307988
0x3e30 0x185fd0000 + 278064
0xfe44cc 0x185fd0000 + 83148
0xfefd0000 + 75668
CoreFoundation
0xa8efc 0x + 904956
CoreFoundation
0xa1cc000 + 903568
CoreFoundation
0xa1cc000 + 894608
CoreFoundation
0xd1cc000 + 38528
GraphicsServices
0xe6d8000 + 49288
0xcd90 0x185fd0000 + 511376
CloudConsoleApp
0xb4e0 main (main.m:16)
libdyld.dylib
0xd768b8 0x180d74000 + 10424
//不过我对着这行代码分析了好久,实在想不出来崩溃的原因。没有任何crash提示信息。
//这个版本Swift代码只有这样一个crash
//后面再看看新crash会不会也是这样
self.resourceType = YWSXXX.shareInstance().getXXXByXXX(self.XXX.pluginId)
实际证明Swift的crash信息非常不准确,能知道崩溃的文件和函数,行号不准确,也不会输出Application Specific Information。比如下面这个crash。
Incident Identifier: D-454B-20B58B
CrashReporter Key:
Hardware Model:
CloudConsoleApp [696]
/var/mobile/Containers/Bundle/Application/E8E24C8B-A47B-425E-863F-A871F273FCA2/CloudConsoleApp.app/CloudConsoleApp
Identifier:
com.aliyun.wstudio.amc.AliyunMobileApp
2.2.0 (2169)
Code Type:
Parent Process:
Date/Time:
10:44:56 +0000
OS Version:
iPhone OS 9.2.1 (13D15)
Report Version:
Exception Type:
Exception Codes: #0 at 0x
Triggered by Thread:
Thread 0 Crashed:
CloudConsoleApp
0x9e80 __TFC15CloudConsoleApp24YWSTouchIDViewController14viewWillAppearfS0_FSbT_ (in CloudConsoleApp) + 1304
CloudConsoleApp
0x9eb0 __TToFC15CloudConsoleApp24YWSTouchIDViewController14viewWillAppearfS0_FSbT_ (in CloudConsoleApp) + 44
0xc74c 0x0000 + 182092
0xc4c0 0x0000 + 181440
0xd0 + 864560
0xd2a6c 0x0000 + 862828
0xd0 + 861844
0xd25fc 0x0000 + 861692
0xf778 0x0000 + 63352
QuartzCore
0xc1eb2c 0xc10000 + 60204
QuartzCore
0xc00 + 38712
QuartzCore
0xc195f8 0xc10000 + 38392
QuartzCore
0xc18c94 0xc10000 + 35988
QuartzCore
0xc189dc 0xc10000 + 35292
QuartzCore
0xc120cc 0xc10000 + 8396
CoreFoundation
0xd0 + 902536
CoreFoundation
0xd632c 0xfc000 + 893740
CoreFoundation
0xd675c 0xfc000 + 894812
CoreFoundation
0x0 + 38528
GraphicsServices
0x0 + 49288
0xcd90 0x0000 + 511376
CloudConsoleApp
0xf988 main (in CloudConsoleApp) (main.m:16)
libdyld.dylib
0xfa68b8 0xfa4000 + 10424
//确实崩溃在viewWillAppear函数中,但是是97行的 as! 导致的,在crash信息里面这两个重要的信息没有暴露出来。
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
//let urlString = YWSXXX.sharedInstance().get("userIcon") as! String
//因为2.1.0重构过登录模块,新的登录模块才会保存 userIcon 这个值
//所以2.2.0覆盖2.1.0之前的版本用 as! 会崩溃,这里改成 as? 了
if let urlString = YWSXXX.sharedInstance().get("userIcon") as? String {
Swift 2.1版本已经非常稳定,苹果将其开源,也表明对Swift的质量和可靠性有足够的信心。开源社区开始涌现一批优秀的Swift库,比如Charts,这个画图的组件很不错。StackOverflow的答案中很多人会同时提供Objective-C和Swift两个版本。目前来看唯一美中不足的问题就是解出来的crash没有Objective-C那么直观了,很多时候都得靠猜。
文/阿呆少爷(简书作者)
原文链接:/p/a5e6e574145b
非常兴奋的告诉大家一个好消息:刚刚在线官网正式上线啦!欢迎大家访问!官网地址:
刚刚在线的使命-让学习iOS开发更简单!我们的团队有30多位实战讲师,将为大家提供更多的技术分享、视频直播、实战项目等等。
本周六技术分享
好消息接连不断,技术分享说来就来!本周六晚上8点,注意时间噢!可以提前关注刚刚在线教育直播间,以免到时候找不到。
技术分享简介:
斗鱼技术分享课程
主题:《App Thinng》
时间:(周六)晚8:00 至 9:00
斗鱼房间:刚刚在线教育
地址:/ggteach
大家可以提前关注。
&&美丽的分割线&&&
编程是一种生活方式
今天在回来的路上看到一个好朋友分享了一篇文章《美国监狱新趋势&学编程》
是的,不可思议。有网友表示:想去美国监狱,包吃住还免费学编程!令人震惊的是:“他们中没有人因再次犯罪而重返监狱,他们走了一条正确的路。”
很多美国人已经意识到编程的重要性!编程不再是一项找工作的技能,而是一种生活方式,每个人都多少应该懂一点编程。
为了呼吁美国人民学习编程知识,奥巴马甚至还亲自挽起袖子写了一段javascript代码,这也让他成为美国历史上第一位会写代码的总统。(虽然写得不怎么样)
国内编程现状
在中国的大学里面,计算机课程只是讲一些理论知识。很多大学生(包括计算机系)毕业之后,很难靠自己掌握的编程知识找到一份工作。这是一件何其可悲的事情。
很多同学无奈之下,会选择线下的培训班,但是培训班的费用高的让人望而却步。有的同学因为昂贵的费用,这一生可能就与编程无缘;
有的同学可能会咬牙坚持贷款2万甚至更多,来学习一项编程的技能。还未入社会,就要背负着为银行打工的重担。
刚刚在线的诞生
刚刚在线的诞生就是为了帮助广大iOS开发爱好者,让学习iOS开发更简单!
刚刚在线推出iOS开发技术直播课程,直播课程将免费开放,直播课程涉及iOS开发常用的控件、网络请求、第三方类库等。
同时,刚刚在线推出iOS开发社群。为社群成员提供高级进阶、在线答疑、实战项目、面试技巧、独立博客、职位推荐等服务。
刚刚在线团队成员来自北京、上海、广州、美国、日本等地方,每一位讲师都是实战派!
女程序员发的一条微博:
“昨晚梦见男朋友和别的女人在逛街,梦里我的第一反应就是查源代码,结果调试半天查不出来为什么显示的那个女人不是我,最后含泪把那个女人注释掉了,再一运行就是我男朋友自己逛街了。”
众网友的神回复:
1、把那个女人的指针指向你即可; (:з」∠)
2、谁让你把男朋友设成public的?;Σ(っ °Д °;)っ
3、加个断点看看那女人是谁; (?ω?)
4、心真软,就应该把他的接口屏蔽掉; (?_?)
5、Protected逛街(youOnly); (?o?_o?)?
6、设计问题,应该采用单例模式; (?o?ω???)
7、没做回归测试; ヽ(  ̄д ̄;)ノ
8、标准做法是做个断言; (?o??o?) ?
9、注释掉了,逛街的参数不用改吗?; (@ ̄ー ̄@)
10、最后含泪把那个女人给注释掉了,再一运行就是我男朋友自己逛街了—>很明显是变量名作用域的问题,改个名就行了(?o??o?) ?
11、还可以有个多线程的算法,把你的优先级设成99,一个idle线程的优先级设成50,把那个女人的优先级设成49。酱紫就永远都调度不到啦 (?o?ω???)
12、那也没关系,那就老调用那个女人。。。你BF放在那里不动。。。养着 (?ω?)
13、上绝招,用goto,做个死循环,让他们逛死 (?o??o?) ?
14、善心点,别goto了,调用exit函数结束进程吧,冤冤相报何时了啊 ヽ(  ̄д ̄;)ノ
15、查一下Log,仅仅只有逛街吗??(????)
来自:/p/Xa51bf.html
由上篇文章将了如何在MAC本地搭建一个Openfire服务器,今天我们就要着手使用 XMPPFramework来开发 基于XMPP 协议的即时通讯IOS 客户端系统。今天主要看登录功能开发,可能有人会质疑,我们都没有开发注册功能,怎么开发登录功能。注册账号我们有捷径,服务器都在本地,当然很好做了。另外就是通过MAC 自带的客户端 Messages 进行注册。
首先,我们需要搭建起来IOS 的工程,并且将XMPPFramework 引入到我们的工程中来,当然我们可以使用源码 直接导入,也可以使用cocoapods来进行依赖。本文直接使用源码来进行开发。由于在Github上的源码有一些问题,所以大家可以来下载相关的XMPPFramework相关的代码。
下载关于XMPPFramework的代码之后,我们需要做的是 创建一个工程,然后将源代码导入到我们的工程中去。当然直接导入并且编译会出现libxml找不到的问题。我们需要在工程中导入libxml2.tbd(ios 9之后的名称) 以及 libresolv.9.tbd(ios 9之后的后缀)。然后在Build Setting的Head search 中加上 头文件的链接地址
${SDKROOT}/usr/include/libxml2
这之后,重新编译工程即可编译成功。后面,我们需要做的就是开发登录功能了,在开始之前,我们还是先看一下怎么注册一个账号吧;登录Openfire后台,创建一个用户。
通过在浏览器中输入 (前提 是 openfire服务器以及mysql服务器都已经启动了)
127.0.0.1:9090
进入如下界面
点击左上角用户/组 进入用户管理界面
然后点击 左侧 导航栏中的新建用户 填写好用户信息就可以了。
到这边基本上用户注册环节 已经结束了。
开发 登录功能,基本上包括 登录界面的开发、XMPP登录逻辑的开发。登录界面我们可以 随便搭建一个登录界面就可以了。我今天主要是说一下 XMPP登录部分。
首先,创建关于XMPPLoginManager类,实现XMPPStreamDelegate,我定义了自己的一个宏,表示使用的Openfire服务器的地址 以及 端口号
#define LocalOpenfire 1
#if LocalOpenfire
#define HOST_NAME @"127.0.0.1"
#define HOST_PORT 5222
#define CONNECT_IDENTIFIER @"@"
#define TIME_OUT 20
然后 定义XMPPStream、XMPPReconnect实例,并且初始化
- (void)initXMPPStream {
self.loginXmppStream = [[XMPPStream alloc] init];
[self.loginXmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
- (void)initXMPPReconnect {
self.loginReconnectManager = [[XMPPReconnect alloc] init];
[self.loginReconnectManager activate:self.loginXmppStream];
// You can also optionally add delegates to the module.
[self.loginReconnectManager addDelegate:self delegateQueue:dispatch_get_main_queue()];
定义 Login按钮点击之后的点击事件调用 XMPPLoginManager中的如下方法进行连接:
#pragma mark -- connect xmpp method for login viewController
- (void)connectXMPPServer:(NSString *)userName password:(NSString *)password {
self.userName = userN
self.password =
NSString *myJid = [NSString stringWithFormat:@"%@%@%@", userName, CONNECT_IDENTIFIER, HOST_NAME];
self.loginXmppStream.myJID = [XMPPJID jidWithString:myJid];
self.loginXmppStream.hostName = HOST_NAME;
self.loginXmppStream.hostPort = HOST_PORT;
NSError *connectError =
[self.loginXmppStream connectWithTimeout:TIME_OUT error:&connectError];
if (connectError) {
NSLog(@"%@", connectError);
[self.loginDelegate loginXMPPConnectError:connectError];
后面就是处理XMPPStream的各种回调就可以了
#pragma mark -- xmppstream delegate
//连接xmpp成功之后,使用密码认证
- (void)xmppStreamDidConnect:(XMPPStream *)sender {
NSError *authError =
[self.loginXmppStream authenticateWithPassword:self.password error:&authError];
if (authError) {
NSLog(@"%@", authError);
[self.loginDelegate loginXMPPDidNotAuthenticate];
//认证通过之后的处理
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender {
NSLog(@"%@", @"认证通过");
[self.loginDelegate loginXMPPDidAuthenticate];
//连接服务器的超时处理
- (void)xmppStreamConnectDidTimeout:(XMPPStream *)sender {
NSLog(@"连接超时");
[self.loginDelegate loginXMPPConnectDidTimeout];
//认证没有通过处理
- (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error {
NSLog(@"认证失败");
[self.loginDelegate loginXMPPDidNotAuthenticate];
基本上这样就可以登录了,登录成功之后,可以跳转到相应的界面。提一下我们 能看到的XMPP交互流程 包括:
1、XMPP 使用用户名去连接服务器;
2、XMPP 连接成功之后,通过密码去服务器认证
3、认证成功之后,处理自己想处理的一下事情。
但其实XMPP 报文交互包括好几步,我就从别人那边摘录一点交互细节过来,就不自己一个个的抓包看了。
C1: 客户端初始化流给服务器
&stream:stream to="127.0.0.1" xmlns="jabber:client"
xmlns:stream="http://etherx.jabber.org/streams" version="1.0"& S1: 服务器向客户端发送流标签作为应答:
&?xml version='1.0' encoding='UTF-8'?&&stream:stream
xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client" from="192.168.1.185" id="fb0cfcad" xml:lang="en" version="1.0"&
S2: 发送 STARTTLS范围
&stream:features&
&starttls xmlns="urn:ietf:params:xml:ns: xmpp-tls"&&/starttls& &mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"&
&mechanism&PLAIN&/mechanism& &mechanism&CRAM-MD5&/mechanism& &mechanism&ANONYMOUS&/mechanism& &mechanism&DIGEST-MD5&/mechanism& &mechanism&JIVE-SHAREDSECRET&/mechanism& &/mechanisms&
&compression xmlns="http://jabber.org/features/compress"&
&method&zlib&/method& &/compression&
&auth xmlns="http://jabber.org/features/iq-auth"/&
&register xmlns="http://jabber.org/features/iq-register"/& &/stream:features&
C2:客户端发送 STARTTLS 命令给服务器:
&starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/&
S3:服务器通知客户端可以继续进行:
&proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/&
C3:TLS 握手成功, 客户端初始化一个新的流给服务器
&stream:stream to="192.168.1.185" xmlns="jabber:client"
xmlns:stream="http://etherx.jabber.org/streams" version="1.0"&
S4:服务器通知客户端可用的验证机制:
&?xml version='1.0' encoding='UTF-8'?&
&stream:stream xmlns:stream="http://etherx.jabber.org/streams"
xmlns="jabber:client" from="192.168.1.185" id="ad6f53e8" xml:lang="en" version="1.0"& &stream:features&
&mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"& &mechanism&DIGEST-MD5&/mechanism& &mechanism&PLAIN&/mechanism&
&mechanism&ANONYMOUS&/mechanism& &mechanism&CRAM-MD5&/mechanism& &/mechanisms&
&compression xmlns="http://jabber.org/features/compress"& &method&zlib&/method& &/compression&
&auth xmlns="http://jabber.org/features/iq-auth"/&
&register xmlns="http://jabber.org/features/iq-register"/& &/stream:features&
C4: 客户端选择一个验证机制:
&auth mechanism="DIGEST-MD5" xmlns="urn:ietf:params:xml:ns:xmpp-sasl"&&/auth&
S5:服务器发送一个 [BASE64] 编码的挑战给客户端:
&challenge xmlns="urn:ietf:params:xml:ns:xmpp-sasl"&cmVhbG09IjE5Mi4xNjguMS4xODUiLG5vbmNlPSJlcEJaZlBxU1p0WGlLYzBqdGpwT0I1a01HMHdiY0hsUmNhOE52ZE9SIixxb3A9ImF1dGgiLGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNz&/challenge&
C5:客户端发送一个[BASE64]编码的回应这个挑战:
&response xmlns="urn:ietf:params:xml:ns:xmpp-sasl"&Y2hhcnNldD11dGYtOCx1c2VybmFtZT0iYWRtaW4iLHJlYWxtPSIxOTIuMTY4LjEuMTg1Iixub25jZT0iZXBCWmZQcVNadFhpS2MwanRqcE9CNWtNRzB3YmNIbFJjYThOdmRPUiIsbmM9MDAwMDAwMDEsY25vbmNlPSJMNDJ1SE1XK2piemh6N1hzdWRndHN1V1VIT2hNZmFLVUJpcU5iR1p2IixkaWdlc3QtdXJpPSJ4bXBwLzE5Mi4xNjguMS4xODUiLG1heGJ1Zj02NTUzNixyZXNwb25zZT1hN2JhMWZlOThiMDc2ZjUzZWUzNTczM2Q5NDMwODJlYSxxb3A9YXV0aCxhdXRoemlkPSJhZG1pbiI=&/response&
S6:服务器通知客户端验证成功
&success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"&cnNwYXV0aD0yNDZlZDcyOTQ3ZjVhYzFiNWQ2ZDc4ZTkxM2QzMmFjMQ==&/success&
C6客户端初始化一个新流给服务器:
&stream:stream to="192.168.1.185" xmlns="jabber:client"
xmlns:stream="http://etherx.jabber.org/streams" version="1.0"&
基本上XMPP的登录细节就已经清楚了。后面我们看一下 注册相关的模块 以及 联系人请求模块的开发。如果想获取源码的话,请转到
本文作者:Terry 专注于技术开发;打滚于IOS 技术领域,偶尔也会迈出脚步探索其他领域
地址:/terrylmay.github.io//XMPP%E5%AE%A2%E6%88%B7%E7%AB%AF%E7%99%BB%E5%BD%95%E5%BC%80%E5%8F%91%E8%AF%A6%E8%A7%A3/
年底了估计有朋友已经坐不住了,前面有一篇文章介绍。你是不是也占几个呢?
跳槽不可避免会遇到面试,有些公司会找一些奇葩的面试题来坑我们。所以我们不得不做好防备、提前备战,怎么感觉跟备考一样呢?
我不得不遗憾的告诉你,这比备考重要多了。面试题做不好,很有可能错过一次大好机会。很早之前我收集了很多面试题,以后都分享出来。大家如果手里有不错的面试题目,可以直接发给我,我的邮箱:,我也会分享给大家!
本文挡会持续更新,欢迎关注公众号iOS开发:iOSDevTip 关注之后回复:面试
1. Object-C有多继承吗?没有的话用什么代替?
cocoa 中所有的类都是NSObject 的子类
多继承在这里是用protocol 委托代理 来实现的 你不用去考虑繁琐的多继承 ,虚基类的概念. ood的多态特性 在 obj-c 中通过委托来实现.
2. Object-C有私有方法吗?私有变量呢?
objective-c – 类里面的方法只有两种, 静态方法和实例方法. 这似乎就不是完整的面向对象了,按照OO的原则就是一个对象只暴露有用的东西. 如果没有了私有方法的话, 对于一些小范围的代码重用就不那么顺手了.
在类里面声名一个私有方法
@interface Controller : NSObject { NSString * }
+ (void)thisIsAStaticM – (void)thisIsAnInstanceM
@interface Controller (private)
- (void)thisIsAPrivateM
@private可以用来修饰私有变量
在Objective‐C中,所有实例变量默认都是私有的,所有实例方法默认都是公有的
3. #import和#include的区别,@class代表什么?
@class一般用于头文件中需要声明该类的某个实例变量的时候用到,在m文件中还是需要使用#import‘
而#import比起#include的好处就是不会引起重复包含
4. 线程和进程的区别?
进程和线程都是由操作系统所体会的程序运行的基本单元,系统利用该基本单元实现系统对应用的并发性。
进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
5. 堆和栈的区别?
管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memory leak。 申请大小:
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出
分配方式:堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。 分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的。
6. Object-C的内存管理?
1.当你使用new,alloc和copy方法创建一个对象时,该对象的保留计数器值为1.当你不再使用该对象时,你要负责向该对象发送一条release或autorelease消息.这样,该对象将在使用寿命结束时被销毁.
2.当你通过任何其他方法获得一个对象时,则假设该对象的保留计数器值为1,而且已经被设置为自动释放,你不需要执行任何操作来确保该对象被清理.如果你打算在一段时间内拥有该对象,则需要保留它并确保在操作完成时释放它.
3.如果你保留了某个对象,你需要(最终)释放或自动释放该对象.必须保持retain方法和release方法的使用次数相等.
7 浅复制和深复制的区别?
答案:浅层复制:只复制指向对象的指针,而不复制引用对象本身。
深层复制:复制引用对象本身。
意思就是说我有个A对象,复制一份后得到A_copy对象后,对于浅复制来说,A和A_copy指向的是同一个内存资源,复制的只不过是是一个指针,对象本身资源
还是只有一份,那如果我们对A_copy执行了修改操作,那么发现A引用的对象同样被修改,这其实违背了我们复制拷贝的一个思想。深复制就好理解了,内存中存在了
两份独立对象本身。
用网上一哥们通俗的话将就是:
浅复制好比你和你的影子,你完蛋,你的影子也完蛋
深复制好比你和你的克隆人,你完蛋,你的克隆人还活着。
这是来自quroa的问题:Why-aren&t-there-a-lot-of-old-programmers-at-software-companies下的一个回答。
很多人会疑问是不是程序员最后只能转管理,是不是到了中年之后就应该放弃编程。看到这个回答后很受触动,尽力翻译出来,有不恰当的地方欢迎指出。
下 个星期我就69岁了。我从1967年开始编程。到现在已经48年了,从COBOL一直写到jQuery。我已经忘掉的编程语言比很多程序员这辈子遇到的还 多。我现在自己接一些项目,因为作为一个员工我完全是个工作狂,即使在我已经三十多岁的时候。我永远不会再去做一份每天工作8小时的传统编程工作。
我 已经写了两三百万行或者四百万行代码,我觉得我至少要写到&额,算了,无所谓。代码写的再多也没有什么意义,除非,这个代码对你关心的人们产生了好的 影响。(原文是: a positive impact on people I care about,和《硅谷》里的make world a better place 真是异曲同工)
变老带来的一个好处是,我不会再相信那些有一个点子就能改变世界的二逼想法。我只想把我应该做的工作做好,然后交给用户一个体验更好的产品。
但 是一个老年程序员有一个非常明显的缺点。这个世界变化的非常快,而且越来越快。15年前,我投身C++,然后我很精通它。大概4年前,我开始沉迷于 jQuery,同时学习怎么把jQuery和C#混在一起(hook jQuery and C#)去快速实现一个用户界面。3年前我从公司退休,于是我又开始关注C#并且沉迷于WordPress。现在是Drupal(php的一个框架)。趋势 就是学习一样新东西对我而言越来越难。我现在还在尝试用本地存储和 Web Workers写一个WordPress插件,调试这些真的让我有点累。
但是我真正要坚持的是要不断的编程,不要停,因为我真的热爱编程,其实我也只会这么一件事。不像人际交往、建立社交圈是我最近二十几年才开始尝试去做。
所以左脑用于编程,右脑用于处理人际关系让我保持着生活的平衡。这肯定因为我已经和一个美丽的女人结婚四十多年,我和我的三个孩子也有着非常和睦的关系。
我给自己设立了一个目标,至少要写50年(到2017年6月)。然后在70岁的时候成为Mankind Project & New Warriors Training Adventure项目联合领袖。非常有挑战性。几年以后你可以再来看看我做的怎么样。
圣诞节对于美国人来说是一个重要的节日。每年的圣诞节苹果公司都会全员放假8天时间,时间日之日。今年也不例外。
昨天登录苹果开发者平台:
就有提示:
提示的很清楚:
我们将于这段时间休假。在此期间,我们会停用一些功能,如 APP 提交等...
在放假这段时间里,苹果将会暂停AppStore推荐、审核、提交、更新等工作。所以这段时间内更新、上架都会受到影响。
元旦之前,想要上架的朋友,必须得抓紧时间啦!
Copyright & 2017 - 李刚
Powered by
为本站提供存储空间

我要回帖

更多关于 安卓在线 的文章