Tag: Objective C

使用Swiftify将SVProgressHUD转换为Swift

Swift被开发人员所喜爱,并且显然是Apple生态系统以及通用编程的未来,因为它已被Apple开源,并且全世界的开发人员都为它做出了积极的贡献。 Swift代码更快,更易读,看起来像脚本语言一样自然有趣。 Objective-C非常强大,大量框架和Apple框架的许多部分都用Objective-C编写。 鉴于Swift现在已经在Swift 5中实现ABI稳定性,因此作为一种语言已经达到了一定程度的稳定性和成熟度,因此通过迁移到Swift来开始将来对我们的代码和框架进行验证始终是一个更好的选择。 SVProgressHUD 是一个非常流行的库,被开发人员广泛使用。 它以其使用简单和简洁的设计而优雅。 Swiftify for Xcode是一个非常强大的工具,可以将整个Objective-C项目转换为Swift。 我用它来转换项目,结果非常好而且很快,但是当我简短地研究了项目代码时,我对代码的结构或功能没有深入的了解。 我意识到最好一次转换一个项目类,测试转换后的类,然后继续重复该过程。 我强烈建议您在自己的代码或经过充分研究并有深入理解的代码上使用Swiftify for Xcode。 如果您要转换不是您自己编写的代码或您不了解的代码,我建议一次迁移一个类,使用现有代码进行测试,然后重复该过程,因为以后将调试整个项目很难。 分而治之总是更好。 我的整体方法可以用图形表示为: 查看SVProgressHUD中的代码结构,我转换文件的顺序如下:- 因此,在将Swiftify用于Xcode之后,我又从头开始,转换的第一个类是SVRadialGradientLayer 。 此类用于添加渐变蒙版类型,并且仅在一个位置调用。 转换SVRadialGradientLayer.m并在SVRadialGradientLayer.h中添加属性和函数。 转换很简单,并且很快即可完成。 只需应用一个修复程序,只需一个简单的Google搜索即可完成。 之后,我从目标中删除了这个Objective-C类,添加了新的Swift文件并运行了该项目,该项目按预期进行了编译和运行,因此我继续下一个文件。 下一个要转换的类是SVProgressIndefiniteAnimatedView 。 此类用于显示两种类型的不确定动画视图,即本机设计和平面设计。 在本机设计中,ProgressHud使用和显示动画视图,在平面设计中,显示签名UIActivityIndi​​catorView 。 我将代码转换为Swift,将属性设为私有,并添加了用于设置和获取属性的函数。 接下来,我从SVProgressAnimatedView类开始,该类负责显示带有进度指示器环的HUD。 它仅支持平面样式,不支持UIActivityIndi​​catorView 。 现在是项目的主类,该主类与外部代码协调并使用这些类来呈现HUD。 这个课程非常复杂。 我使用了前面提到的技术,例如利用setter和getters函数,将所有类函数放在不同的类扩展中。 该类使用自身的单个实例,即它是一个独立的Singleton类。 所有的类函数最终都使用此Single Instance 。 在最终完成之后,我还花了一些时间清理不推荐使用的功能。 我从类函数开始,一次完成转换。 然后是更大的实例方法,它们是库的内容。 慢慢地,文件被转换,并在助手编辑器中使用Swiftify查找原始源代码。 代码转换花了一些时间,有几个问题让我使用原始SVProgressHUD文件和Swift版本文件运行项目,并通过查看运行时值的差异进行调试。 这就是在上面的流程图中 ,我不会删除原始的Objective-C文件的原因,直到代码转换完成并且Swift代码正在运行并经过测试。 现在,如果我们愿意,可以通过不删除@objc前缀,并在用作代码接口的函数和属性中添加@objc前缀来保持与Objective-C的兼容性。 测试之后,我从函数和self中删除了@objc ,并对库进行了增强以使其成为线程安全的 。 现在,您可以从任何线程使用该库,始终可以从主线程创建并评估单个实例 […]

与无法识别的选择器对抗时学习目标C

与无法识别的选择器对抗时学习目标C 前提: 我试图在我的项目中实施AdManager单例类,但遇到一个问题,试图使其调用广告SDK。 https://i.gyazo.com/a9b3c81c22d46935f9937bc976bce248.mp4 好吧,那不是很漂亮。 一些其他背景。 我选择单例方法的想法是,我们不能在这个类中制造多个对象。 当我们引用此类时,我们都希望引用该对象。 我不认为问题在单例实现的背后,但是我不知道代码是如何工作的..那是个问题。 我的最终目标-我只希望有一位广告经理可以引用广告展示位置,广告信息,并在不同的视图中展示它们。 为此,我希望能够在我的任何控制器中调用AdManager并将其分配给我一个广告。 简单。 然后,插入各种其他货币化SDK,并即时进行交换,这样我就可以很好地划分游戏和货币化分区。 因此,事不宜迟,让我们深入研究如何首先声明单例,以确保我正确地做到了。 这是在做什么 +(id)sharedInstance { 静态AdManager * sharedInstance = nil; 静态dispatch_once_t OnceToken; dispatch_once(&onceToken,^ { sharedInstance = [[self alloc] init]; }); 返回sharedInstance; } 逐行细分: +(id)sharedInstance “ +”号表示这是类函数,而不是实例函数。 类方法以+开头,而实例方法以-开头。 可以将类方法与类名一起使用。 实例方法要求存在该类的实例。 实例(或对象)是您根据蓝图建造的实际房屋。 一堂课就像一栋房子的蓝图:您只有一个蓝图,并且(通常)您不能仅凭蓝图就做那么多。 https://stackoverflow.com/questions/1053592/what-is-the-difference-between-class-and-instance-methods (id)表示指向任何Objective-C对象的指针。 作为目标c,这意味着我们需要确保保留/释放。 编译器非常高兴您可以将任何对象隐式转换为id。 这意味着这是一个类方法,它返回指向某个对象的指针。 https://stackoverflow.com/questions/7987060/what-is-the-意思-of-id http://www.peachpit.com/articles/article.aspx?p=377302&seqNum=2 静态AdManager * sharedInstance = nil; […]

使用Pod组织代码库

当涉及第三方库时,Cocoapods是救生员! 将库集成到我们的项目从未如此简单。 在没有cocoapods支持的情况下,集成库需要下载框架和捆绑软件,然后将它们拖到我们的Xcode项目中,链接到我们新添加的二进制文件,然后添加一些iOS链接器标志。 哦! 然后对每个需要使用的库重复这些操作,或者…如果任何工作失败,请重新执行此过程。 😣 所有这些都由cocoapods处理,对于我们来说,这通常是一个单行命令(在您启动pod文件并将其填充了所有必需的库之后)。 这不是有关如何使用cocoapods的文章。 掌握它非常容易,并且已经有很多方法。 相反,我们将寻求使用cocoapods的功能来组织我们的代码库。 我的作业需要重构和更新已经存在的现有应用程序。 因此,我的团队没有选择项目结构的自由。 我们必须处理的代码库具有紧密耦合的组件,并且在多个实例中重复了很多代码片段。 我们也不想破坏已经在运行的代码,因为我们必须尽早为最近发布的iOS设备提供支持。 但是团队知道当前的设计和项目结构将很快成为瓶颈。 当团队中的其他成员添加新功能和服务时,我的任务是逐步重建现有代码库。 最初,我很难确定什么是不妨碍预定发布日期的合适解决方案。 我在这里解救的一件事是椰壳足。 它帮助我解耦了代码,没有破坏功能,也没有被证明是开发过程中的决定因素。 迁移后,处理特定模块变得更加容易! 此外,以这种方式进行组织使集成新功能和SDK成为轻而易举的事。 我们从来不知道使用像这样的cocoapods可以节省我们的工作时间。 我们甚至最终私下托管了不同的模块,并将其分发给黑客马拉松和筛选过程。 好吧..如此称赞可可豆。 让我们看看魔术! 为了演示,我们考虑必须创建一个包含多个组件的应用程序。 在这里,组件是我们为组织代码而创建的pod。 从概念上讲,这将如下图所示。 请记住,始终从文件’ MyApp.xcworkspace’运行项目。 的。 一旦我们通过终端“ pod安装”以集成组件,就会创建xcworkspace文件。 按下视图内的按钮后,“ MyApp ”将在视图控制器上显示警报。 警报生成代码将驻留在我们应用程序的组件(pod)中,我们将其称为“ AlertServices ”。 因此,视图控制器将只需要处理逻辑即可在主项目中呈现和消除警报。 这些警报的创建,样式和自定义将在AlertServices内部进行。 首先,让我们在Xcode中创建一个新项目。 然后选择Cocoa Touch Framework模板。 现在,我们在项目根目录的AlertServices目录内创建一个子目录(只是为了使代码更有条理),并将其命名为MyAppAlerts。 在将目录添加到项目源之后,我们然后创建一个名为MyAppAlerts的类。 我将使用以前在此文件中创建的快餐栏视图,然后在这里完成工作! 下一步,我们现在将移至拥有“ AlertServices.xcodeproj ”文件的目录。 在这里,我们需要创建一个新文件并将其命名为。 podspec (在我们的例子中是AlertService .podspec […]

Каждому视图повсплывающемуменю

Всегдаприятно,когдавприложениипродуманымелочи。 Однимизтакихнебаловажныхэлементовинтерфейсаявляетсявсплывающееменю UIMenuController中的UIMenuController 。 Вэтойстатьемыразберемся,какработатьсовсплывающимменю,скакимиограниченияеиин Собираемэлементыменю Итак,мысобираемсяпоказатьвсплывающиеменюдлянекоторогоUIView。 Дляначалаопределимся,какиеименноэлементыбудетпредлагатьнашеменюпользователю。 UIItemView 。 Черезнеговконтроллерменюпередаетсяотображаемыйтекстидействие,происходящеепривабе let item = UIMenuItem(title:“ Send”,action: #selector (sendTapped)) Рассмотримпоподробнеевторойпараметр— action 。 Окей,этоселекторнекоторогометода,которыйбудетвызванпривыбореэлементаменю。 Значит,этотметоддолженбытьгде-тореализован,ногдеименно? Еслибыэтобылаобычнаякнопка,тополучателяможноуказатьвметодеaddTarget: sendButton.addTraget( self ,action: #selector (sendTapped),for:…) 在UIMenuItem上添加UIMenuItem 。 Кудажетогдаотправится action ? Обратимсякдокументации: 未指定目标; 通过响应者链的正常遍历找到合适的目标。 响应链 ? Похоже,преждечемдвигатьсядальше,нампридетсянемногоразобратьсявпроцессеобработиисобы。 响应者链иfirstResponder UIResponder ,UIUI应用程序,UI控制器中的Любоеприложениеможнопредставитьввидеиерархииобъектовкласса Каждыйтакойобъектспособенполучатьсобытия:нажатия, 运动 -событияили UIControlEvents ,илибообрабатыватьполученноесобытие,либопередаватьегоследующему 应答 “увиерархии。 响应者 Но,преждечемпопасть,событиедолжнобытьполученокем-товпервуюочередь。 ПоэтомудлякаждоговприложениисобытияUIKitопределяетнаиболееподходящийобъектклас firstfirstResponder’омтотобъектстановится 响应者, […]

井井有条的项目是一个清晰的文件结构加上一个标记的代码。

我们尝试组织生活,因此时间表是一个很好的工具。 当我们要清洁桌子时,我们将所有东西整理好了。 这些想法我们可以应用于我们的代码,因为它是我们日常生活的一部分。 第1阶段-项目文件结构 我希望您没有一个包含.xcodeproj文件之类的文件列表的项目。 有数十个没有任何功能分类的文件。 您可以说:嗯,所有文件都应组织在项目文件中。 让我们打开百宝箱。 我们能看到什么? 像这样: 请不要说您以相同的方式进行操作。 最后一个示例由Apple提供,但是当您应该为具有大量类和职责的真实项目提供支持时–与以前计划相比,您将花费更多的时间进行搜索和准备。 此示例来自MVC范例,在该范例中我们按类型创建了分组。 结果,我们开发了一个快速的基础和难扩展的结构。 解决方案1: 我为自己找到的最好的体系结构之一是按功能分组。 Andrew Cherkashyn在他的文章:以xCode组织iOS项目文件的最佳方法中对此进行了描述。 所描述的结构更加复杂,但易于扩展。 此外,我们可以轻松地将其修改为其他架构:MVP,MVVM,VIPER…在下面提供的示例中,我们的项目结构如下所示: 阶段2 –类或文件中的结构 仅当M不代表Massive时,我才喜欢MVC模式。 苹果将​​其用作基本概念,并且效果很好。 如果要在模型/视图/控制器/等中更好地组织代码,该怎么办? 它们为我们提供了来自Objective-C的#pragma mark的极大可能性。 在Swift中,我们将其称为// MARK: note。 不幸的是,一些开发人员跳过了此功能。 他们使自己的代码变得肮脏,并且不将其分离为不同类型的功能。 作为示例,它可以像这样: 我们在那里: 在文件的顶部,存在方法addAlbum(_:) -一个动作方法; 在中间,有两个枚举: SegueIdentifier和CellIdentifier ; 在CellIdentifierds.下声明的变量CellIdentifierds. 完全没有标记。 我的第一意见: 解决方案2: 1.您应该在指定的具体区域内组织枚举/属性/方法/扩展/等。 另外,不要将代码放在任何需要的地方。 如果使用多个枚举,最好将其描述在一个位置,例如在文件或类的顶部: 2.使用// MARK: -仅几行代码可更快地在文件中查找内容。 快速示例: 班级成绩 恢复: 井井有条的项目加上相同的代码样式,可让您和您的团队更好地理解项目及其所有组件。 我坚持认为,清晰的代码可以提高生产率并缩短问题解决时间。 例子: […]

iOS-一个新的LAN网络扫描程序库已经诞生

它是如何开始的 2011年3月,当我为iOS开发我的第一个真实项目时,IT Buddy最初是一个IP计算器,现在被认为是真正的IT Buddy! 从第一天开始,我就考虑在IT Buddy中添加LAN扫描程序的情况,但是我的知识有限,没有任何我可以使用的开源项目。 五年后,仍然没有像样的LAN扫描程序库。 有几个可用的LAN扫描仪,但尚未投入生产。 没有适用于iOS的不错的LAN扫描程序库 很多人在StackOverflow上询问如何实现LAN扫描仪,所以我决定将所有部分放在一起(SimplePing,SimplePingHelper,LAN-Scan和MacFinder),并创建一个不错的开源库来通过iOS设备扫描网络。 。 体面的意思是: 不仅可以扫描所有子网/ 24 快速搜索而不会阻塞UI 使用默认的LAN扫描技术来ping和查询ARP表。 显示可用主机的IP和MAC地址。 根据MAC地址显示设备品牌 MMLanScan 因此,名称为MMLanScan,并且非常易于使用。 在此处下载并在您的项目中复制MMLanScan文件夹! 在您的控制器中导入MMLANScanner #import“ MMLANScanner.h” 将MMLANScannerDelegate添加到您的控制器 @interface YourViewController() 声明MMLANScanner属性 @property(nonatomic,strong)MMLANScanner * lanScanner; 开始扫描 [self.lanScanner停止]; self.lanScanner = [[MMLANScanner alloc] initWithDelegate:self]; self.connectedDevices = [[NSMutableArray alloc] init]; [self.lanScanner启动]; 实现委托方法以接收事件 -(void)lanScanDidFindNewAddressWithIP:(NSString *)ipAddress MACAddress:(NSString *)macAddress和Hostname:(NSString *)hostname; -(void)lanScanDidFinishScanning; -(void)lanScanProgressPinged:(NSInteger)pingedHosts from:(NSInteger)overallHosts; -(void)lanScanDidFailedToScan; 怎么运行的 […]

iOS iOS中的多线程入门

随着我们所有移动设备中多核处理芯片的出现,它带来了在应用程序中同时执行多个任务的可能性。 在iOS中, 为了使应用程序的UI保持响应状态,所有繁重的任务都添加到了新线程中,例如,网络调用。 这些线程通常在后台运行,并在必要时发送回叫以更新UI。 苹果文档中已完美说明了多线程需求,它说: OS X或iOS中的每个进程(应用程序)都由一个或多个线程组成,每个线程代表通过应用程序代码执行的单个路径。 每个应用程序都从一个线程开始,该线程运行该应用程序的主要功能。 应用程序可以产生其他线程,每个线程都执行特定功能的代码。 为了方便和安全地管理这些额外的线程,我们需要一个框架,例如dispatch multi 实现多线程的方法: –大中央派遣 – NSThread – NSOperationQueue 本博客假定您对这些类型有基本的了解。 比较这些方法时: Code/Structural Origins: GCD是基于C的底层API。 NSOperation和NSOperationQueue是Objective-C类(GCD上的包装器)。 NSThread是一个NSObject(使用pthreads)。 Complexity comparison: 对于GCD实施非常轻巧 NSOperationQueue非常复杂且重量级 NSThread只是pthread的包装器,因此也使其轻巧。 NSOperation advantages over GCD and NSThread: 您可以: 因此,在两个NSOperation之间建立依赖关系,使开发人员可以按特定顺序执行任务。 一旦任务开始执行,就暂停,取消,恢复NSOperation,因此可以控制该操作的生命周期。 监视操作的状态,例如:准备,执行或完成。 指定可以同时运行的最大排队操作数。 显然,NSOperationQueue为您提供了对操作的更多控制。 一旦确定了要使用的方法,就需要确定其顺序和优先级。 Order of Operation: 队列可以有两种类型:串行队列或并发队列,分别分别同步和异步运行任务 Priority of operations: 优先级定义为称为QoS的服务质量,分为以下四种类型: 现在,我们通过预测几个示例的输出来尝试了解这些操作。 在尝试回答下面的代码输出之前,让我们看一下dispatch_async和dispatch_sync的文档: Dispatch_async: 🤞🏼声明void dispatch_async(dispatch_queue_t队列,dispatch_block_t块)👥讨论此函数是用于将块提交到调度队列的基本机制。 […]

使用Swiftify更好地发送消息

许多开发人员在初次尝试使用该语言时就对Objective-C的消息发送语义感到困惑。 消息发送的语义使得可以“调用”空对象上的方法。 您实际上并不是在调用方法,而不是将消息发送到没有地址的地方。 如果您是在Swift中构建应用,则不必担心理解Objective-C消息发送。 这就是为什么最新版本的Swiftify的Objective-C至Swift Converter大大改进了我们处理消息发送的方式。 在Objective-C中,属性只是方法周围的语法糖,可以像调用方法一样调用它。 @implementation TestViewController:UIViewController-(IBAction)graphButtonClicked:(id)sender { GraphViewController * graphViewController = [[[[self splitViewController] viewControllers] lastObject]; }@结束 注意对[self splitViewController]而不是self.splitViewController 。 在Swift中,您不能引用self.splitViewController()因为该方法不存在。 我们的转换器按预期处理此问题: 类TestViewController:UIViewController { @IBAction func graphButtonClicked(_ sender:Any){ 让graphViewController = splitViewController?.viewControllers.last as? GraphViewController } } 对[self splitViewController]属性getter的调用将替换为Swift中适当的属性调用。 甚至splitViewController的可选性都是正确的! 您可以在此处测试示例。 Objective-C如何处理方法和消息还有另一个有趣的方面。 Objective-C方法的参数名称不是方法签名的一部分。 @interface TestViewController:UIViewController -(NSString *)greetPerson:(NSString *)personName; @ end @ implementation TestViewController:UIViewController-(NSString *)greetPerson:(nonnull NSString […]

UILocalNotification iOS

本地通知使您的应用可以通知用户有关不需要使用服务器的内容的信息。 与从服务器触发的远程通知不同,本地通知是在应用内安排和触发的。 通常,通知的目标是增加用户与应用程序的交互,从而邀请或诱使用户打开并与其交互。 iOS 10中已弃用UILocalNotification。请改用UserNotifications框架。 安排本地通知 确保您看到注册本地通知以使其正常运行: 迅速 让通知= UILocalNotification() notification.alertBody =“您好,本地通知!” notification.fireDate = NSDate()。dateByAddingTimeInterval(10)// 10秒后 UIApplication.sharedApplication()。scheduleLocalNotification(通知) 目标C UILocalNotification * notification = [[UILocalNotification alloc] init]; notification.alertBody = @“您好,本地通知!” notification.fireDate = [NSDate dateWithTimeIntervalSinceNow:10]; //现在10秒钟后[[UIApplication sharedApplication] scheduleLocalNotification:notification]; 要在iOS模拟器中查看通知,请键入^⌘H(control-command-H)返回首页,然后键入⌘L(command-L)以锁定设备。 等待几秒钟,然后将出现通知(此外观将根据“注册本地通知”中讨论的通知类型而有所不同): 在通知上滑动即可返回到应用程序(请注意,如果您在第一个视图控制器的viewDidLoad,viewWillAppear,viewDidAppear等中调用了此方法,则会再次安排该通知)。 立即显示本地通知 如果要立即显示本地通知,请致电: 迅捷3 UIApplication.shared.presentLocalNotificationNow(notification) 迅捷2 UIApplication.sharedApplication()。presentLocalNotificationNow(通知) 目标C [[UIApplication sharedApplication] presentLocalNotificationNow:notification]; 使用此方法的一个优点是您不必设置自己的fireDate和timeZone属性。

如何对iOS的Mode属性UIImageView进行设置

视图的内容模式属性指示如何布置其内容。 在“界面生成器”中,可以在“属性”检查器中选择各种模式。 让我们使用两个图像视图来查看各种模式如何工作。 缩放以填充 图像的高度和宽度被拉伸以匹配UIImageView的大小。 纵横比拟合 图像的最长边(高度或宽度)被拉伸以匹配视图。 这使图像尽可能大,同时仍显示整个图像且高度或宽度不失真。 (我将UIImageView背景设置为蓝色,以便其大小清晰可见。) 外观填充 图像的最短边(高度或宽度)被拉伸以匹配视图。 像“宽高比”一样,图像的比例不会偏离其原始宽高比。 重画 重绘仅适用于需要自行缩放和调整大小的自定义视图。 我们没有使用自定义视图,因此我们不应该使用重绘。 请注意,这里的UIImageView只是给我们提供了与“缩放以填充”相同的结果,但是它在后台进行了更多工作。 中央 图像在视图中居中,但图像的长度和宽度未拉伸。 最佳 图像的顶部边缘在视图顶部水平居中,并且图像的长度和宽度未拉伸。 底部 图像的底部边缘在视图底部水平居中,并且图像的长度和宽度未拉伸。 剩下 图像的左边缘在视图的左侧垂直居中,并且图像的长度和宽度未拉伸。 对 图像的右边缘在视图的右侧垂直居中,并且图像的长度和宽度未拉伸。 左上方 图像的左上角位于视图的左上角。 图像的长度和宽度未拉伸。 右上 图像的右上角位于视图的右上角。 图像的长度和宽度未拉伸。 左下方 图像的左下角位于视图的左下角。 图像的长度和宽度未拉伸。 右下 图像的右下角位于视图的右下角。 图像的长度和宽度未拉伸。 笔记 如果内容(在我们的情况下为图像)与视图的大小相同(在我们的情况下为UIImageView),则更改内容模式不会有明显的区别。 请参阅此问题,以获取有关UIImageView以外的视图的内容模式的讨论。 在Swift中,要设置以编程方式设置内容模式,请执行以下操作: imageView.contentMode = UIViewContentMode.scaleToFill imageView.contentMode = UIViewContentMode.scaleAspectFit imageView.contentMode = UIViewContentMode.scaleAspectFill imageView.contentMode = UIViewContentMode.redraw imageView.contentMode […]