首页 文章 精选 留言 我的

精选列表

搜索[移动app],共10000篇文章
优秀的个人博客,低调大师

5款便捷的App帮你预定出租车

在我们开始之前,我想先提一条建议:在下载应用之间,最好是检查一下地理服务区。很多应用只在特定国家或者特定城市很好用。我曾尝试了列出一个尽可能覆盖面广的应用榜单,但是确实存在很明显的地域限制--不过我选择这些应用都是有原因的。 1、Uber Uber(如图A)是一款在多个国家都广受欢迎的出租车服务应用。这款应用的基本理念就是,你可以通过Uber司机来安排乘坐,他们通常是使用私家车的普通人。Uber应用可以用于选择Uber司机来接你。 图A 这款应用详单简单,但是有一点让我受不了:你必须注册并提供支付信息(例如信用卡号或者PayPal账户),甚至只是你刚开始看看这款应用有些什么之前。此外,当你完成的时候似乎没有办法删除你的支付信息或者删除帐号。 Uber应用支持iOS、安卓和Windows Phone。 2、Easy Taxi Easy Taxi(如图B)是请求出租车的最好的应用之一。我喜欢这款应用有两点。首先,它几乎可以在任何地方使用,它覆盖了有大约40个国家。另外一点,就是它的简洁性。这款应用的叫车流程相当小白--相信我,当我起得非常早要赶早上5点的飞机时,这是一个非常好的优点。 图B Easy Taxi支持iOS、安卓和Windows Phone。 3、mytaxi mytaxi(如图C)是另外一款免费的预约出租车的应用。与Uber一样,mytaxi要求你得创建一个账户,但是如果你只是想看看并了解下这个应用,你可以跳过选择支付方法的部分。这款应用本身非常简单。你只需要验证你在地图上的GPS位置是否正确,然后点击确认接送地点。美版网站声称已经连接了4.5万辆出租车。 图C mytaxi支持iOS、安卓、Windows Phone和黑莓。 4、GroundLink Car and Limo Service GroundLink Car and Limo Service(如图D)是针对那些喜欢“司机的黑车服务”多过传统出租车的人。这款应用在美国已经连接了4.5万辆车,同时覆盖其他110个国家。 图D 这款应用的功能与mytaxi几乎相同,你必须验证你在地图上的位置,然后点击确认接送地点以安排行程。 GroundLink Car and Limo Service支持iOS和安卓。 5.WOW Taxi WOW Taxi(如图E)与其他我提到的应用相比有一些局限性,因为它只能在纽约市使用。尽管如此,我必须选择这款应用是因为它满足了一个非常现实的需求。WOW Taxi中的WOW代表“Wheels on Wheels”。这个有些不寻常的名字,是因为它是为残疾人士在曼哈顿出行而专门设计的。WOW Taxi与其他出租车应用相比与众不同之处在于,它只用于调度无障碍出租车。正如我所说的,这项服务目前仅限于在纽约式提供,但我希望能够扩到的其他地区。 图E 这款应用本身和其他应用的使用方法相同--你必须确认GPS位置,然后预定行程。 WOW Taxi支持iOS和安卓。 原文发布时间为:2015-2-14 本文作者:孙博 本文来自云栖社区合作伙伴至顶网,了解相关信息可以关注至顶网

优秀的个人博客,低调大师

iOS解决App启动时闪屏问题(swift)

创建一个工具类MTAppHelper import UIKit fileprivate let isIphone4 = Int(kScreenH) == 480 fileprivate let isIphone5 = Int(kScreenH) == 568 fileprivate let isIphone6 = Int(kScreenH) == 667 fileprivate let isIphonePlus = Int(kScreenH) == 736 /// 工具类 class MTAppHelper { /// 根据机型获取指定机型的图片 /// /// - returns: 指定手机类型的图片 static func fetchLaunchImage() -> UIImage? { var imageName: String! if isIphonePlus { imageName = "Default-736h" } else if isIphone6 { imageName = "Default-667h" } else if isIphone5 { imageName = "Default-568h@2x~iphone" } else { imageName = "Default@2x~iphone" } return UIImage(named: imageName) } } 加载UI时调用方法 showSplashScreenImage(); /// 闪屏图片视图 lazy var splashImageView: UIImageView = UIImageView(frame: kScreenBounds) /// 展示闪屏图片 private func showSplashScreenImage() { //使用工具类方法 splashImageView.image = ZSAppHelper.fetchLaunchImage() UIApplication.shared.keyWindow?.addSubview(splashImageView) }

优秀的个人博客,低调大师

检测iOS的APP 性能的一些方法

首先如果遇到应用卡顿或者因为内存占用过多时一般使用Instruments里的来进行检测。但对于复杂情况可能就需要用到子线程监控主线程的方式来了,下面我对这些方法做些介绍: Time Profiler 可以查看多个线程里那些方法费时过多的方法。先将右侧Hide System Libraries打上勾,这样能够过滤信息。然后在Call Tree上会默认按照费时的线程进行排序,单个线程中会也会按照对应的费时方法排序,选择方法后能够通过右侧Heaviest Stack Trace里双击查看到具体的费时操作代码,从而能够有针对性的优化,而不需要在一些本来就不会怎么影响性能的地方过度优化。 Allocations 这里可以对每个动作的前后进行Generations,对比内存的增加,查看使内存增加的具体的方法和代码所在位置。具体操作是在右侧Generation Analysis里点击Mark Generation,这样会产生一个Generation,切换到其他页面或一段时间产生了另外一个事件时再点Mark Generation来产生一个新的Generation,这样反复,生成多个Generation,查看这几个Generation会看到Growth的大小,如果太大可以点进去查看相应占用较大的线程里右侧Heaviest Stack Trace里查看对应的代码块,然后进行相应的处理。 Leak 可以在上面区域的Leaks部分看到对应的时间点产生的溢出,选择后在下面区域的Statistics>Allocation Summary能够看到泄漏的对象,同样可以通过Stack Trace查看到具体对应的代码区域。 开发时需要注意如何避免一些性能问题 NSDateFormatter 通过Instruments的检测会发现创建NSDateFormatter或者设置NSDateFormatter的属性的耗时总是排在前面,如何处理这个问题呢,比较推荐的是添加属性或者创建静态变量,这样能够使得创建初始化这个次数降到最低。还有就是可以直接用C,或者这个NSData的Category来解决https://github.com/samsoffes/sstoolkit/blob/master/SSToolkit/NSData%2BSSToolkitAdditions.m UIImage 这里要主要是会影响内存的开销,需要权衡下imagedNamed和imageWithContentsOfFile,了解两者特性后,在只需要显示一次的图片用后者,这样会减少内存的消耗,但是页面显示会增加Image IO的消耗,这个需要注意下。由于imageWithContentsOfFile不缓存,所以需要在每次页面显示前加载一次,这个IO的操作也是需要考虑权衡的一个点。 页面加载 如果一个页面内容过多,view过多,这样将长页面中的需要滚动才能看到的那个部分视图内容通过开启新的线程同步的加载。 优化首次加载时间 通过Time Profier可以查看到启动所占用的时间,如果太长可以通过Heaviest Stack Trace找到费时的方法进行改造。 监控卡顿的方法 还有种方法是在程序里去监控性能问题。可以先看看这个Demo,地址https://github.com/ming1016/DecoupleDemo。 这样在上线后可以通过这个程序将用户的卡顿操作记录下来,定时发到自己的服务器上,这样能够更大范围的收集性能问题。众所周知,用户层面感知的卡顿都是来自处理所有UI的主线程上,包括在主线程上进行的大计算,大量的IO操作,或者比较重的绘制工作。如何监控主线程呢,首先需要知道的是主线程和其它线程一样都是靠NSRunLoop来驱动的。可以先看看CFRunLoopRun的大概的逻辑 int32_t__CFRunLoopRun() { __CFRunLoopDoObservers(KCFRunLoopEntry); do { __CFRunLoopDoObservers(kCFRunLoopBeforeTimers); __CFRunLoopDoObservers(kCFRunLoopBeforeSources);//这里开始到kCFRunLoopBeforeWaiting之间处理时间是感知卡顿的关键地方 __CFRunLoopDoBlocks(); __CFRunLoopDoSource0();//处理UI事件 //GCDdispatchmainqueue CheckIfExistMessagesInMainDispatchQueue(); //休眠前 __CFRunLoopDoObservers(kCFRunLoopBeforeWaiting); //等待msg mach_port_twakeUpPort=SleepAndWaitForWakingUpPorts(); //等待中 //休眠后,唤醒 __CFRunLoopDoObservers(kCFRunLoopAfterWaiting); //定时器唤醒 if(wakeUpPort==timerPort) __CFRunLoopDoTimers(); //异步处理 elseif(wakeUpPort==mainDispatchQueuePort) __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__() //UI,动画 else __CFRunLoopDoSource1(); //确保同步 __CFRunLoopDoBlocks(); }while(!stop&&!timeout); //退出RunLoop __CFRunLoopDoObservers(CFRunLoopExit); } 根据这个RunLoop我们能够通过CFRunLoopObserverRef来度量。用GCD里的dispatch_semaphore_t开启一个新线程,设置一个极限值和出现次数的值,然后获取主线程上在kCFRunLoopBeforeSources到kCFRunLoopBeforeWaiting再到kCFRunLoopAfterWaiting两个状态之间的超过了极限值和出现次数的场景,将堆栈dump下来,最后发到服务器做收集,通过堆栈能够找到对应出问题的那个方法。 staticvoidrunLoopObserverCallBack(CFRunLoopObserverRefobserver,CFRunLoopActivityactivity,void*info) { MyClass*object=(__bridgeMyClass*)info; object->activity=activity; } staticvoidrunLoopObserverCallBack(CFRunLoopObserverRefobserver,CFRunLoopActivityactivity,void*info){ SMLagMonitor*lagMonitor=(__bridgeSMLagMonitor*)info; lagMonitor->runLoopActivity=activity; dispatch_semaphore_tsemaphore=lagMonitor->dispatchSemaphore; dispatch_semaphore_signal(semaphore); } -(void)endMonitor{ if(!runLoopObserver){ return; } CFRunLoopRemoveObserver(CFRunLoopGetMain(),runLoopObserver,kCFRunLoopCommonModes); CFRelease(runLoopObserver); runLoopObserver=NULL; } -(void)beginMonitor{ if(runLoopObserver){ return; } dispatchSemaphore=dispatch_semaphore_create(0);//DispatchSemaphore保证同步 //创建一个观察者 CFRunLoopObserverContextcontext={0,(__bridgevoid*)self,NULL,NULL}; runLoopObserver=CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, &runLoopObserverCallBack, &context); //将观察者添加到主线程runloop的common模式下的观察中 CFRunLoopAddObserver(CFRunLoopGetMain(),runLoopObserver,kCFRunLoopCommonModes); //创建子线程监控 dispatch_async(dispatch_get_global_queue(0,0),^{ //子线程开启一个持续的loop用来进行监控 while(YES){ longsemaphoreWait=dispatch_semaphore_wait(dispatchSemaphore,dispatch_time(DISPATCH_TIME_NOW,30*NSEC_PER_MSEC)); if(semaphoreWait!=0){ if(!runLoopObserver){ timeoutCount=0; dispatchSemaphore=0; runLoopActivity=0; return; } //两个runloop的状态,BeforeSources和AfterWaiting这两个状态区间时间能够检测到是否卡顿 if(runLoopActivity==kCFRunLoopBeforeSources||runLoopActivity==kCFRunLoopAfterWaiting){ //出现三次出结果 if(++timeoutCount3){ continue; } //将堆栈信息上报服务器的代码放到这里 }//endactivity }//endsemaphorewait timeoutCount=0; }//endwhile }); } 有时候造成卡顿是因为数据异常,过多,或者过大造成的,亦或者是操作的异常出现的,这样的情况可能在平时日常开发测试中难以遇到,但是在真实的特别是用户受众广的情况下会有人出现,这样这种收集卡顿的方式还是有价值的。 堆栈dump的方法 第一种是直接调用系统函数获取栈信息,这种方法只能够获得简单的信息,没法配合dSYM获得具体哪行代码出了问题,类型也有限。这种方法的主要思路是signal进行错误信号的获取。代码如下 staticints_fatal_signals[]={ SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGTRAP, SIGTERM, SIGKILL, }; staticints_fatal_signal_num=sizeof(s_fatal_signals)/sizeof(s_fatal_signals[0]); voidUncaughtExceptionHandler(NSException*exception){ NSArray*exceptionArray=[exceptioncallStackSymbols];//得到当前调用栈信息 NSString*exceptionReason=[exceptionreason];//非常重要,就是崩溃的原因 NSString*exceptionName=[exceptionname];//异常类型 } voidSignalHandler(intcode) { NSLog(@"signalhandler=%d",code); } voidInitCrashReport() { //系统错误信号捕获 for(inti=0;isignal(s_fatal_signals[i],SignalHandler); } //oc未捕获异常的捕获 NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler); } intmain(intargc,char*argv[]){ @autoreleasepool{ InitCrashReport(); returnUIApplicationMain(argc,argv,nil,NSStringFromClass([AppDelegateclass])); } } 使用PLCrashReporter的话出的报告看起来能够定位到问题代码的具体位置了。 NSData*lagData=[[[PLCrashReporteralloc] initWithConfiguration:[[PLCrashReporterConfigalloc]initWithSignalHandlerType:PLCrashReporterSignalHandlerTypeBSDsymbolicationStrategy:PLCrashReporterSymbolicationStrategyAll]]generateLiveReport]; PLCrashReport*lagReport=[[PLCrashReportalloc]initWithData:lagDataerror:NULL]; NSString*lagReportString=[PLCrashReportTextFormatterstringValueForCrashReport:lagReportwithTextFormat:PLCrashReportTextFormatiOS]; //将字符串上传服务器 NSLog(@"laghappen,detailbelow: %@",lagReportString); 测试Demo里堆栈中的内容,超过了微信正文字数,所以本文省略了 本文作者:佚名 来源:51CTO

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册