草庐IT

Swift5: App模块化

DrEnhart 2023-03-28 原文
AppDemo.png

目标是将序列化和网络请求做成单独的framework并且可以替换.
所有公用的东西都放在公共库Common中.

workspace 'AppDemo.xcworkspace'
platform :ios, '13.0'

use_frameworks!
load './Api/api_v1.rb'

target :Common do
  project 'Common/Common.xcodeproj'

  pod 'Alamofire'

 end

target :AppDemo do
    project 'App/AppDemo/AppDemo.xcodeproj'
    pod 'Common', :path => './Common/'
    
    load_api_pods
end

target :ApiModelSerialize do
    project 'Api/ApiModelSerialize/ApiModelSerialize.xcodeproj'

    pod 'Common', :path => './Common/'
    pod 'SwiftyJSON'
end

target :ApiNetwork do
    project 'Api/ApiNetwork/ApiNetwork.xcodeproj'

    pod 'Common', :path => './Common/'
    pod 'Alamofire'
end

load_api_pods是一个单独.rb文件, 想替换framework的话就修改这个文件.

def load_api_pods
    pod 'ApiModelSerialize', :path => './Api/ApiModelSerialize/'
    pod 'ApiNetwork', :path => './Api/ApiNetwork/'
end

序列化(ApiModelSerialize)

在ApiModelSerialize这个framework中声明一个protocol

protocol ISwiftyJson {
    init()
    
    mutating func dFromJSON(json: JSON)
    func dToJSON() -> JSON
}

再为一些基本类型扩展遵循一下这个protocol

extension Int: ISwiftyJson {
    mutating func dFromJSON(json: JSON) {
        self = json.intValue
    }
    
    func dToJSON() -> JSON {
        var json = JSON()
        json.intValue = self
        return json
    }
}

需要序列化的Model也需要扩展遵循一下这个protocol

extension Member: ISwiftyJson {
    
    public func dFromJSON(json: JSON) {
        Id = json["Id"].intValue
    }

    public func dToJSON() -> JSON {
        var json = JSON()
        json["Id"].intValue = Id
        return json;
    }
}

现在序列化这个是基本上算是实现了, 但是还需要封装一下.
Common中声明一个protocol

public protocol IApiModelSerialize {
    mutating func aLoadFromJSONString<T>(model: T, str: String)
    func aToJSONString<T>(model: T) -> String
    func aConvertJSONStringToArray<T>(type: T.Type, str: String) -> [T] where T: ServerModel
}

ApiModelSerialize中遵循一下这个protocol

public class PApiModelSerialize: IApiModelSerialize {

    public init() {
        
    }
    
    public func aLoadFromJSONString<T>(model: T, str: String) {
        if var m = model as? ISwiftyJson {
            m.dFromJSON(json: JSON(parseJSON: str))
        }
    }
    
    public func aToJSONString<T>(model: T) -> String {
        if let m = model as? ISwiftyJson {
            return m.dToJSON().rawString()!
        }
        fatalError("Can't deSerialize")
    }
    
    public func aConvertJSONStringToArray<T>(type: T.Type, str: String) -> [T] where T : IServerModel {
        let arrayValue = JSON(parseJSON: str)
        var array = [T]()
        for j in arrayValue {
            if let jsonString = j.1.rawString() {
                var t = T()
                t.aLoadFromJSONString(str: jsonString)
                array.append(t)
            }
        }
        return array
    }

}

Common中声明一个protocol

public protocol IServerModel {
    init()
    
    mutating func aLoadFromJSONString(str: String)
    func aToJSONString() -> String
}

ServerModel作为所有Model的父类遵循这个protocol

open class ServerModel: IServerModel {
    public required init() {
        
    }
    
    open func aLoadFromJSONString(str: String) {
        Api.pModelSerialize.aLoadFromJSONString(model: self, str: str)
    }
    
    open func aToJSONString() -> String {
        return Api.pModelSerialize.aToJSONString(model: self)
    }
}

Model序列化的时候调用aLoadFromJSONString这个方法就可以了.

网络请求(ApiNetwork)

Common中声明一个protocol

public protocol IApiNetwork {
    func aRequest<T>(_ params: ServerParam, handler: IServerRequestHandler<T>?) where T: IServerModel
}

ApiNetwork中遵循一下这个protocol

public class PApiNetwork: IApiNetwork {

    public init() {
        
    }
    
    public func aRequest<T>(_ params: ServerParam, handler: IServerRequestHandler<T>?) where T : IServerModel {
        ServerUtil_Alamofire.fRequest(params, handler: handler)
    }

}

实际使用中调用一下就可以了

open class ServerUtil_Account {

    private static let c_Controller = "Account"
    
    public static func Login(loginParam: LoginParam, handler: IServerRequestHandler<MyProfile>?) {
        let param = ServerParam(post: true)
            .controller(c_Controller)
            .action("Login")
            .add(value: loginParam)
        Api.pNetwork.aRequest(param, handler: handler)
    }

}

关联声明与实现

ApiModelSerialize和ApiNetwork声明在Common中, 实现在具体framework中, 在App中需要将他们关联起来.

class AppConfigImpl {

    init() {

    }
    
    func connect() {
        Api.pModelSerialize = PApiModelSerialize()
        Api.pNetwork = PApiNetwork()
    }

}
class AppDelegate: UIResponder, UIApplicationDelegate {
    
    var window: UIWindow?
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        AppConfigImpl().connect()
        return true
    }

}

最后用登录功能做一下验证

        ServerUtil_Account.Login(loginParam: loginParam, handler: IServerRequestHandler<MyProfile>({data in
            print(data.Member?.NickName)
        }, fail: { (failInfo) in
            
        }))

代码

代码放在github, 有需要自取.
https://github.com/drenhart/AppDemo.git

有关Swift5: App模块化的更多相关文章

  1. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  2. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  3. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  4. ruby - 当使用::指定模块时,为什么 Ruby 不在更高范围内查找类? - 2

    我刚刚被困在这个问题上一段时间了。以这个基地为例:moduleTopclassTestendmoduleFooendend稍后,我可以通过这样做在Foo中定义扩展Test的类:moduleTopmoduleFooclassSomeTest但是,如果我尝试通过使用::指定模块来最小化缩进:moduleTop::FooclassFailure这失败了:NameError:uninitializedconstantTop::Foo::Test这是一个错误,还是仅仅是Ruby解析变量名的方式的逻辑结果? 最佳答案 Isthisabug,or

  5. ruby-on-rails - 每次我尝试部署时,我都会得到 - (gcloud.preview.app.deploy) 错误响应 : [4] DEADLINE_EXCEEDED - 2

    我是Google云的新手,我正在尝试对其进行首次部署。我的第一个部署是RubyonRails项目。我基本上是在关注thisguideinthegoogleclouddocumentation.唯一的区别是我使用的是我自己的项目,而不是他们提供的“helloworld”项目。这是我的app.yaml文件runtime:customvm:trueentrypoint:bundleexecrackup-p8080-Eproductionconfig.ruresources:cpu:0.5memory_gb:1.3disk_size_gb:10当我转到我的项目目录并运行gcloudprevie

  6. ruby - 获取模块中定义的所有常量的值 - 2

    我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c

  7. ruby - 模块嵌套代码风格偏好 - 2

    我的假设是moduleAmoduleBendend和moduleA::Bend是一样的。我能够从thisblog找到解决方案,thisSOthread和andthisSOthread.为什么以及什么时候应该更喜欢紧凑语法A::B而不是另一个,因为它显然有一个缺点?我有一种直觉,它可能与性能有关,因为在更多命名空间中查找常量需要更多计算。但是我无法通过对普通类进行基准测试来验证这一点。 最佳答案 这两种写作方法经常被混淆。首先要说的是,据我所知,没有可衡量的性能差异。(在下面的书面示例中不断查找)最明显的区别,可能也是最著名的,是你的

  8. ruby-on-rails - 如何重命名或移动 Rails 的 README_FOR_APP - 2

    当我在我的Rails应用程序根目录中运行rakedoc:app时,API文档是使用/doc/README_FOR_APP作为主页生成的。我想向该文件添加.rdoc扩展名,以便它在GitHub上正确呈现。更好的是,我想将它移动到应用程序根目录(/README.rdoc)。有没有办法通过修改包含的rake/rdoctask任务在我的Rakefile中执行此操作?是否有某个地方可以查找可以修改的主页文件的名称?还是我必须编写一个新的Rake任务?额外的问题:Rails应用程序的两个单独文件/README和/doc/README_FOR_APP背后的逻辑是什么?为什么不只有一个?

  9. ruby-on-rails - 使用 config.threadsafe 时从 lib/加载模块/类的正确方法是什么!选项? - 2

    我一直致力于让我们的Rails2.3.8应用程序在JRuby下正确运行。一切正常,直到我启用config.threadsafe!以实现JRuby提供的并发性。这导致lib/中的模块和类不再自动加载。使用config.threadsafe!启用:$rubyscript/runner-eproduction'pSim::Sim200Provisioner'/Users/amchale/.rvm/gems/jruby-1.5.1@web-services/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:105:in`co

  10. ruby - 使用 postgres.app 在 rvm 下要求 pg 时出错 - 2

    我正在使用Postgres.app在OSX(10.8.3)上。我已经修改了我的PATH,以便应用程序的bin文件夹位于所有其他文件夹之前。Rammy:~phrogz$whichpg_config/Applications/Postgres.app/Contents/MacOS/bin/pg_config我已经安装了rvm并且可以毫无错误地安装pggem,但是当我需要它时我得到一个错误:Rammy:~phrogz$gem-v1.8.25Rammy:~phrogz$geminstallpgFetching:pg-0.15.1.gem(100%)Buildingnativeextension

随机推荐