Tag: 编程

使用LLDB在Xcode中进行调试

数据冒险 犯了错误 有时,我们会对不正确的事情做出假设。 这种说法似乎很明显,这是人的天性。 编写软件时,最好质疑您的假设是否正确。 很多时候,您会发现,仔细检查后发现事情与最初出现的情况并不完全相同。 🤔挑战你的假设 使用Xcode时,可以质疑我们的假设的一种方法是使用调试器。 调试器是一种工具,可让您使用细粒度的控件检查和操纵代码执行。 通过调试,您可以更好地了解您的代码在做什么。 这篇文章旨在简要概述Xcode中的调试以及一些可以帮助您的工具。 我打算就调试主题撰写一系列文章,这是第一篇。 调试的主题非常广泛,本文并不旨在提供完整的概述。 如果您觉得缺少什么,请继续关注本系列的更多帖子。 另外,请随时给我评论。 崩溃的土地之旅 这听起来可能有些奇怪,但是可以将代码崩溃视为旅途。 当您点击运行时,它开始运行并编译。 在此过程中,它继续使用方法并具有许多特性。 最终,它成功地找到了坠机土地。 当您开始调试时,您只有一小幅图片。 您有起点和终点,但要知道如何到达那里,就需要追溯旅程的步骤。 为了帮助您完成旅程,Apple向您赠送了一个有价值的物品LLDB调试器。 控制台和LLDB LLDB是Apple提供的软件调试器,它是Xcode中的标准调试工具。 LLDB是一个功能强大的工具,可将应用程序分解为各个组件。 它的用途不仅限于Xcode IDE,即使您无法访问其源代码,也可以使用LLDB分解并检查应用程序。 鉴于功能和用途的广泛性,本文的含义更像是粗略的概述,我不想通过详细研究这些内容而超出范围。 调用堆栈 使用LLDB,我们能够检查调用堆栈以及堆栈中的特定堆栈帧 。 调用堆栈是由应用程序创建的数据结构,用于跟踪其所有行为。 数据结构 堆栈数据结构只是一个队列,在队列中添加的最后一个元素是从中返回的第一个元素(LIFO队列-先进先出)。这与物理世界中的情况大同小异:一堆砖的顶部(如果您从底部取出,即添加的第一块砖,它们都将崩溃。) 堆叠框架 在调用堆栈中有称为堆栈帧的结构。 堆栈框架包含有关为其创建执行的信息。 在调试时,许多此类信息可能会变得有用。 数据范围从局部变量到完成时返回的内存地址。 苹果文档: 程序运行时,它将有关正在执行的操作的信息存储在称为调用栈的数据结构中。 每次调用方法时,程序都会在调用堆栈的顶部推入一个新的堆栈框架 ,其中包含以下内容:传递给该方法的参数(如果有),该方法的局部变量(如果有的话)以及指向该地址的地址。方法调用完成后返回。 断点 如果您不熟悉代码断点,请允许我给您简要介绍一下。 在Xcode中,断点使您可以在特定点中断代码的执行。 这很有用,因为它使您可以在给定的时刻详细检查应用程序的状态。 断点类型 象征绕道 在进一步进入断点之前,让我们先谈谈符号化。 符号化是将内存地址映射到更简单的函数名称。 返回我们以前计划的编程 处理断点时,重要的是要了解有不止一种类型。 让我们简要地谈谈一些重要的类型: […]

Swift:forIn和forEach循环!

Swift提供了各种类型的循环进行迭代。 即使对于正在学习编程语言的新开发人员,也很容易理解和使用。 在这里,我想描述两种类型的for循环 ,乍一看似乎很令人困惑。 它们的工作方式相似,但是两者之间存在一些基本差异。 我在WordCount对象的函数中都尝试过。 下面是操场的快照。 如果您在操场上方看到直升机视图,则表明这两个for循环之间完全没有区别,以访问或循环访问数组的元素。 这是使用forIn和forEach的两个区别! 1)您不能使用break或Continue语句退出当前的闭包调用或跳过forEach循环中的后续调用,但可以在forIn循环中执行此操作。 2)在ForEach循环中使用return语句仅针对闭包中的当前调用退出,不会跳过后续调用,但ForIn循环也退出所有后续后续调用。 和上面的操场一样, forEach跳过了单词“ two”的打印语句的执行,这意味着它不会超出printByForEach函数。 而forIn跳过了所有随后的print语句的执行,这意味着它不在printByForIn函数中。 快乐编码,继续!!!

用户关闭本地通知后会发生什么?

TLDR:如果将本地通知设置为在用户关闭本地通知权限时触发,则该通知仍会在预期的时间触发(如果用户稍后打开权限)。 本地通知是任何iOS开发人员工具箱中的有用工具。 如果您要构建任何类型的警报工具,则几乎没有其他选择。 不幸的是,许多用户无法区分本地通知和推送通知,并且会拒绝两者的权限。 最近,我正在开发一个应用程序,用户可以在其中注册以获得自己喜欢的事件的警报。 即使用户不允许我发送本地通知,我仍将其设置为在所需时间重复(我不会讨论如何设置本地通知,但这是苹果公司有关如何设置它们的说明)。 那么,那些发送给用户的本地通知怎么了? 更重要的是,如果我说服用户打开权限,通知是否会按计划发送? 让我们设置一个场景: 当用户拒绝了通知授权时,我将本地通知设置为每天2:00 PM重复。 下午1:30,用户授予我发送本地通知的权限。 下午2点会发生什么? 通知是按计划发送的,还是因为初始化时没有权限而从未设置? 在上述情况下,即使我在用户关闭通知的情况下设置了通知,通知也将照常发送。 由此看来,可以肯定地说,如果用户的权限仍然处于脱机状态,Apple只是抑制了您发送的通知。 希望这可以节省一些时间! 非常感谢您的阅读! 如果您喜欢这个故事,请在 Twitter上 关注我,在 那里我发布有关产品管理,工程和设计的文章。

如果您不知道使用Objective-C在做什么,则为React Native动态更新Javascript资源

对于正在工作的项目,我正在创建一个React Native应用程序。 React Native的好处是您可以从远程服务器加载javascript包(可以说是应用程序的大脑)。 这意味着您可以进行更新和更改,而无需经过App Store批准过程。 不利的一面是,在应用程序实际加载之前,需要一两秒钟的时间来加载捆绑软件。 除非您有一些花哨的Objective-C或Swift“加载”动画,否则它只会显示白屏。 我没有iOS编程方面的经验,所以我决定做第二件事-从设备本地加载捆绑软件。 我能够整理本指南中的大部分内容,但其中一些我必须自己弄清楚。 所以你想动态更新你的React Native App 在工作中,我们最近在应用程序中发布了第一个React Native组件,并且我一直在考虑如何(以及是否… medium.com) React Native为您提供了将JS捆绑软件存储在应用程序捆绑软件中的选项,这几乎为您提供了即时的加载时间。 我可以使用该机制来做我想要的。 首先,我需要检查是否有下载的JS捆绑包,或者是否需要使用应用程序的捆绑包: //这是应用程序本身的文档目录。 NSString * documentDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES)firstObject]; // filePath代表下载的包所在的位置。 它位于应用程序的documents目录中。 NSString * filePath = [documentDir stringByAppendingPathComponent:@” main-loaded.jsbundle”]; NSURL * codeLocation = [NSURL URLWithString:filePath]; //如果执行路径中没有文件,则使用应用程序包 如果(![[NSFileManager defaultManager] fileExistsAtPath:filePath]){ //加载应用程序包的javascript jsCodeLocation = [[NSBundle mainBundle] URLForResource:@“ main” withExtension:@“ jsbundle”]]; […]

为iOS工程师的工作做好准备

移动应用工程师的要求很高。 同时,它被认为是很难获得的工作之一。 我将介绍您可以采取的基本策略和流程,为您将来的工作做好准备。 我需要知道些什么? 如果您在线搜索面试问题,您会发现奇怪的逻辑难题问题,例如旧金山有多少个窗户。 现在,大多数公司都不再浪费时间在这些问题上,不要花时间在这些问题上。 这就是Google停止询问奇怪,疯狂的面试问题的原因 当您考虑要被Google聘用需要什么时,您可能会记得它臭名昭著的艰难面试…… www.businessinsider.com 标准面试流程如下 电话筛选 编码电话筛选 行为面试 编码面试 这次,我将专注于编码电话筛选和编码采访。 那你需要知道什么? 答案很简单,iOS应用程序开发。 大多数面试官想了解您是否是一名出色的iOS应用工程师。 即使有些公司会要求您回答疯狂的算法问题,但这些问题通常与优化等日常工作相关。 准备面试 我通常会建议初级开发人员花一些时间来复习他们的知识。 目标C 可可SDK OO基本原则 阅读Apple的Objective-C指南以了解您的知识差距。 通过面试问题示例来复习Cocoa SDK知识也是一个好主意。 20个iOS开发人员面试问题| 编码器 有即将面世的iOS开发人员职位面试吗? Codementor Matt一直在进行12年的技术面试…… www.codementor.io 当您回答这些问题时,请切实考虑。 例如,对于诸如“解释强,弱和复制之间的区别?”之类的问题,将其改为“在什么情况下,您会使用强,弱或复制?”。 这将帮助您不记住但以实际的方式理解该概念。 基本的OO原则有助于证明您可以编写良好的代码。 没有人愿意雇用任何弄乱代码库的人。 一如既往的好起点是Head First系列。 首先,面向对象的分析和设计涵盖了如何开始思考面向对象。 当我申请目前的工作时,Robert Martin的敏捷软件开发,原理,模式和实践也非常有帮助。 本书通过大量示例代码介绍了OO原理。 我是否需要了解尖端技术和算法 我个人认为,除非公司正在使用诸如RFP,Swift等之类的尖端技术,否则您无需审查这些尖端技术。这仅仅是因为它们会显示出您的好奇心和兴趣,却没有显示出您编程技能的基本基础。 对于那些尖端技术,我不会太担心。 算法很重要,但在完善iOS知识之后才出现。 对于Google和Microsoft等大公司来说,算法变得越来越重要。 本文有助于为那些大公司做准备。 编码训练营结束后,我花了3个月时间申请工作。 这是我学到的。 刚毕业时发生的事情很少谈论Bootcamper的旅程-当您搜索… medium.freecodecamp.com 本文为iOS工程师提供了很好的问题清单。 […]

如何在Windows上使用Xamarin绑定Fat iOS框架

使用Xamarin开发Android项目时,我没有遇到任何麻烦。 但是,使用Xamarin构建iOS应用程序时,这是完全不同的体验—更复杂。 在本文中,我将分享我使用Xamarin绑定DynamsoftBarcodeReader.framework的经验。 将iOS框架与Xamarin绑定 下载 DynamsoftBarcodeReader.framework是用于条形码检测的SDK。 用Linkwith.cs文件链接依赖项 在Visual Studio 2015中创建一个iOS绑定库项目: 将DynamsoftBarcodeReader.framework \ DynamsoftBarcodeReader重命名为DynamsoftBarcodeReader.framework \ DynamsoftBarcodeReader.a ,然后将静态库拖到项目中。 IDE将自动生成相应的DynamsoftBarcodeReader.linkwith.cs文件: DynamsoftBarcodeReader.framework依赖于libc ++。1.dylib 。 参考ObjCRuntime.LinkWithAttribute类, DynamsoftBarcodeReader.linkwith.cs编写如下: using System; using ObjCRuntime; [assembly: LinkWith (“DynamsoftBarcodeReader.a”, LinkTarget.ArmV7 | LinkTarget.Simulator, ForceLoad = true , LinkerFlags = “-lc++.1”)] 使用Objective Sharpie生成ApiDefinition.cs ApiDefinition.cs是定义API合同的地方,该文件描述了如何将基本的Objective-C API投影到C#中。 您可以为库手动定义所有API,也可以使用仅在macOS上运行的Objective Sharpie自动生成定义。 这是为DynamsoftBarcodeReader.framework生成ApiDeifinition.cs的命令: sharpie -tlm- do -not-submit bind -framework ~/Desktop/DynamsoftBarcodeReader.framework -sdk iphoneos10.2 […]

学习Swift和iOS开发第12部分:多态

在本文中,您将通过阅读有关多态的方法结束对面向对象编程的基础研究。 除了成为一个很酷的词外,多态性是成为程序员时要理解的一个非常重要的概念。 在开发人员求职面试中通常会被问到:“您能定义’多态性’吗?”我们将打破多态性的含义,含义以及它的实际方式,而不是像鹿一样大开眼界。在代码中播放。 什么是多态? 长期以来对多态性的编程定义是:“多态性允许表达某种合同,可能有许多类型以不同的方式实现该合同,每种类型均根据自己的目的。” 这可能只是教科书的定义,但是这里的基本概念是我们的代码可以以许多不同的形式出现,并且其功能可以以不同的方式实现。 这可能仍然令人困惑,没关系。 让我们构建一个代码示例,因为这样更容易理解多态。 创建一个新项目 首先,如果尚未打开Xcode,请点击Create New Playground 。 为其命名,如Polymorphism ,然后单击Next 。 选择某个位置以保存此.playground文件,然后单击“ Create以保存它。 您应该会看到类似下面的屏幕。 删除左侧的所有样板代码,但根据需要保留import UIKit 。 Creating a base Class with default functions 首先,我们将创建一个名为Shape的类,该类具有area属性和一个用于计算形状面积的函数。 将以下内容添加到您的游乐场: 类Shape { var区域:Double? func computeArea(valueA:Double,valueTwo:Double){ } } 我们的基类Shape包含了我们需要的一切-一个用于存储面积的变量和一个用于计算具有两个输入值的面积的函数。 让我们创建一个子类以继承Shape类。 为了证明多态性,我们需要做的是遵守Shape设置的“合约”,该合约具有一个calculateArea函数。 创建一个三角形子类 添加以下类,并覆盖Playground底部的函数calculateArea(valueA:valueB:) : 类Shape { var区域:Double? func computeArea(valueA:Double,valueB:Double){ } } 三角形:形状{ 覆写func computeArea(valueA:Double,valueB:Double){ 面积=(值A […]

iOS应用内购买和订阅

真的很简单。 看一下下面的代码。 让我们来看看它。 一些关键概念是: SKPaymentQueue : 保留所有事务以进行进一步处理的队列 SKProduct :在Itunes中声明的产品与所有可用信息联系在一起 SKPayment :购买产品的意图 SKPaymentTransaction :有关SKProduct的事件 SKProductRequest :请求获取有关提供产品ID的SKProducts的信息 SKProductResponse :包含所需产品的响应。 它由两个列表组成:产品和invalidProductIdentifiers。 第一个将包含成功获取的SKProducts,第二个将包含未能与SKProduct相关的所有标识符。 如果您获得无效的标识符,这是一个故障排除列表,可以帮助您。 确保合同,税务和银行信息已完成 确保正确拼写ProductID 确保AppID是显式的(没有通配符(*)) 确保配置文件是正确的配置文件 确保在产品说明中启用了待售清算选项 确保产品处于批准状态 确保不拒绝对App Store的最后一次App评论 现在,首先,通过以下几行,您可以轻松地创建一个SKProductRequest。 let request = SKProductsRequest(productIdentifiers:productIDs) request.delegate =自我 request.start() 由于以下方法是回调,因此请确保实现SKProductsRequestDelegate。 func productsRequest(_请求:SKProductsRequest,did接收响应:SKProductsResponse) 在那里,您将获得适用于您的应用程序的所有SKProducts。 要进行购买并创建SKPayment。 让付款= SKPayment(产品:产品) SKPaymentQueue.default()。add(付款) 确保在允许用户进行购买之前,始终要获取产品。 这些SKProducts将在其中局部化价格,因此您应该显示它。 这样可以确保您始终将应用程序中的数据始终保持最新,因为应用程序中的价格错误可能会导致Apple将其从App Store中删除。 您可能还会在流程中注意到“ 外部事件”部分。 交易可以在您的应用程序外部发生。 假设您的用户在系统设置中更改了其订阅类型,或者您的延期交易获得了用户父母的批准,那么除非您期望它们,否则您将无法告知。 因此,始终在AppDelegate中,在您的应用程序开始时,将该应用程序订阅到PaymentQueue。 这样,您将确保您不会错过任何事件。 现在,有时该帐户将无法使用。 […]

关于两个图书馆的故事

这不是关于您的典型库的故事,而是关于编程中的库的故事。 在这种情况下,库是程序可以使用的预编译模块的集合-无论是函数,变量,类还是数据结构。 通常,库对于存储经常使用的模块很有用,因此当程序运行所述模块时,并非每个程序都必须显式链接某个模块。 有两种类型的库,静态库和动态库。 在深入探讨关键区别之前,对您来说,重要的是要了解程序(在这种情况下为C程序)的编译方式。 编译分为四个步骤,其中最后一个阶段是链接器。 链接器采用在上一步中创建的程序的目标代码以及该函数使用的函数的所有其他目标文件,并创建一个可执行文件。 让我们看一下包含静态库的程序和包含动态库的程序的链接阶段的两个示例。 示例—静态库 您创建了一个程序calculation_static.c ,该程序运行函数get_product(int a, int b) 。 编译后的汇编程序短语之后,您的函数现在将转换为目标代码。 作为链接阶段的第一步,链接器将使用calculation_static.c的目标代码,并使用该目标代码生成可执行文件。 但是等等,链接器将在所有库中搜索get_product(int a, int b)函数。 链接器找到它后,它将复制get_product(int a, int b)的目标代码,并将其粘贴到get_product(int a, int b)为get_product(int a, int b)创建的可执行文件中。 优点:静态链接的最大特点是可执行程序,如果它是第一次运行,它将始终运行。 该代码不会被破坏。 缺点—例如,如果有多个函数,假设我们的calculation_static.c包含100个函数,而我们包含另一个C程序calculation2_static.c ,其中包含200个函数,那么您需要在其中包含所有300个函数的目标代码。您的可执行文件。 假设您是通过静态链接生成可执行文件的,而用户则将这个可执行文件用于其程序。 几个月过去了,包含get_product(int a, int b)函数的库的创建者完全更改了该函数。 这就是问题所在,用户几个月前使用的可执行文件具有旧的get_product(int a, int b)函数,而不是新版本。 用户将不得不使用该库再次编译原始C程序,并获取该可执行文件以更新其版本。 本质上,每次更新库时,您都必须重新编译程序。 如何创建-要创建静态库,最基本的工具是名为“ ar”(档案)的程序。 该程序可以修改静态库中的目标文件,列出目标文件的名称以及其他各种内容。 ar rc libraryName.a filename.o filename2.o filename3.o […]

TIL:重新定基

当我第一次开始基础调整时,我发现它令人恐惧。 我认为肯定需要进行重大更改,覆盖我为特定分支所做的所有工作,而成功做到这一点是不可能的。 但是,经过几次失败的尝试,我实际上可以说我在另一边还活着,现在,我喜欢变基!!! 因此,对于外行来说,这是您需要重新设置基准的方案: –您是从master分支开始的,但是其他人同时将他们的更改合并到master,因此您需要合并这些更改。 应用更改的最好方法是重新设置基准。 如果将rebase命名为其他名称,例如说“ update”或“ modernize”或“ get-wid-it”,我认为更多的人会发现rebasing很有趣。 首先,在尝试重新设置基准之前,可以通过备份所做的更改使自己省心。 您可以通过以下方式做到这一点: 创建一个临时分支,该分支将冻结您的分支更改,直到重新定基础 复制并保存您已更改的任何文件,或将整个项目本地保存在计算机上 因此,现在,世界就在您的牡蛎上,而您必须彻底出错,才能完全失去所有工作。 因此,这是有关如何重新设置基准的简短教程: 在分支机构的基础项目目录中,在终端中运行: git rebase master -i ←’i’表示交互式,它使您可以管理和修改提交历史记录。 您将在分支上看到提交列表,并且可以选择pick , squash , drop等等。它们中的每一个都是有用的,并且具有不同的用途,但是为了简单起见,在本教程中,我不再赘述。 您可以按原样离开并pick每个提交(或压缩除第一个提交以外的所有提交)。 如果没有合并冲突,您将看到以下消息: Successfully rebased and updated refs/heads/your-branch-name. 但是,您可能会有合并冲突。 同样, merge conflicts是一个令人恐惧的名称-如果将其称为“需要编辑”或“选择武器”或“购物”,它将更容易获得。 因此,这是纠正合并冲突的方法: git status ←这将向您显示哪些文件存在合并冲突 open file-name-that-has-merge-conflict ←然后,在IDE中打开每个文件,然后选择所需的代码(您将在HEAD上看到该版本,并在本地分支上看到该版本)。 git add file-name-that-had-merge-conflict ←添加/保存更改 git rebase –continue ←继续基础 您可能需要重复上述步骤几次(每次正在处理的提交中存在合并冲突时,一次)。 最后,您应该看到令人垂涎的消息: […]