This profile

  • Topic: This is CoderStar talking about his study method.
  • Tips: Simple version of PromiseKit design ideas; How to distinguish between AdHoc/AppStore with profile.
  • Interview module: the meaning and difference of isMemberOfClass and isKindOfClass.
  • Good blog: collated several articles about Swift Pointers, Swift attribute wrappers.
  • Learning Materials: Introduce three machine learning websites.
  • Development tools: site to help parse Shell scripts: ExplainShell.

This topic

@zhangferry: After talking with @Zhanfei last week, I have the idea to interview all the bloggers. On the one hand, blogger + interview can introduce excellent developers to you; on the other hand, the interview form is convenient to get to know bloggers closely and learn their thinking and learning methods. This is a trial run. If you have any better questions, please leave us a comment.

The blogger for this issue is also a co-editor of Fish Weekly: CoderStar.

Blogger interview

Zhangferry: Please introduce yourself and your official account

I am CoderStar, located in Beijing. At present, my main work is related to iOS. I have some dabbles in both the front end and the back end.

Public account: CoderStar, share the technical knowledge related to the big front-end, just talk about the technical stuff, the current content is mainly iOS related, and will share some technical knowledge related to the Vue front-end and so on. At present, the contents of the public account articles are their own original, very welcome to contribute some good articles, everyone a progress.

Zhangferry: Why do you want to write an official account? Write public number to have what benefit bring?

The reason for writing the public account at the beginning is actually quite simple,

1. Because I have accumulated some scattered notes in the past, I want to sort them out.

2. I feel that my work experience has reached a certain stage, and it is time to comb through the knowledge and build my own knowledge system.

3, is to share some of their accumulated technical knowledge, everyone to communicate, to create a good technical circle, a good technical circle is too important.

The benefits of writing the public account:

1. Writing articles not only enables me to have a more thorough understanding of a knowledge point, but also enhances my writing ability. For technical knowledge, self-understanding is a stage, and writing in a simple way is a higher stage;

2, can know a lot of friends, peer on the road will not be lonely, such as and flying brother is to know.

Zhangferry: What interesting things are you studying recently? Could you tell us what you plan to do in the next few articles?

Recently I have been working on optimization, and the next few articles may be biased towards optimization series or underlying related.

Zhangferry: How can I spare some time to write blog every week? Do you have any good learning methods to share?

I now update frequency is an article on Monday, general weekday evening will go to see some article involves information code and do some practice, and accumulated some notes, notes to polymerization in weekend time, form the article, the process or are tired, after all, sometimes work is busy, but must hold to the things, Give yourself a goal, can not casually break more, after all, there is a second break more.

Learning methods: say, my attitude for technology is more optimal solution practice +, when saw some good articles, will my post will in principle or practice a do-it-yourself, consider what are the disadvantages of this method, and around this technology points to think about to have a better solution, constantly in search of a more optimal solution.

The development of Tips

RunsCode, zhangferry

How to smooth out the design of complex logic flow

During development, we often encounter the following problems:

  • Operational priority issues
  • New functions (delay, polling, condition check, etc.) are gradually derived during use.
  • Stepwise callback hell

Talk is cheap, show code

/ / 1
func function0(a) {
    obj0.closure { _ in
        // to do something
        obj1.closure { _ in
            // to do something                      
            obj2.closure { _ in
                .
                objn.closure { _ in
                       .
                }         
            }             
        }        
    }
}

or
/ / 2.
func function1 {
    ifMeet the activity0Condition {// to do something
    } else ifMeet the activity1Condition {// to do something
    } else ifMeet the activity2Condition {// to do something
    }
    .
    else {
        // to do something}}Copy the code

Looking at the above code we can draw the following conclusions:

  • In any case it’s a process or a condition, right
  • Readability is good, but maintainability is poor, and the second revision error rate is high
  • There is no extensibility, only increasing lines of code, conditional branching, and deeper callbacks
  • If the feature is upgraded to add things like delay and polling, it is not supported at all
  • Reusability can be said to be none

The solution

  • Implementing a containerElementCarry all external implementation logic
  • The containerElementIt is linked in a one-way linked list and automatically executes the next one after execution
  • An abstract conditional logic helper is aggregated inside the containerPromise, optionally extend the behavior to check whether an external implementation can execute the next one on the listElement(It can be visually understood as the valve of water pipeline, electric circuit switch, etc., of course, there will be more complex valves and electrical switches)
  • Manages its own lifecycle without the need for strong external references
  • The containerElementCan be implemented by inheritance, seeNSOperationdesign

Example

private func head(a) -> PriorityElement<String.Int> {
    return PriorityElement(id: "Head") {  (promise: PriorityPromise<String.Int>) in
        Println("head input : \(promise.input ?? "")")
        self.delay(1) { promise.next(1) }
    }.subscribe { i in
        Println("head subscribe : \(i ?? -1)")
    }.catch { err in
        Println("head catch : \(String(describing: err))")
    }.dispose {
        Println("head dispose")}}// This is a minimalist way to create element, 
// using anonymous closure parameters and initializing default parameters
private func neck(a) -> PriorityElement<Int.String> {
    return PriorityElement {
        Println("neck input : \ [$0.input ?? -1)")
        $0.output = "I am Neck"
        $0.validated($0.input = = 1)
    }.subscribe { . }.catch { err in . }.dispose { .}}// This is a recommended way to create element, providing an ID for debugging
private func lung(a) -> PriorityElement<String.String> {
    return PriorityElement(id: "Lung") { 
        Println("lung input : \ [$0.input ?? "1")")
        self.count + = 1
        //
        $0.output = "I am Lung"
        $0.loop(validated: self.count > = 5, t: 1)
    }.subscribe { . }.catch { err in . }.dispose { .}}private func heart(a) -> PriorityElement<String.String> {}
private func liver(a) -> PriorityElement<String.String> {}
private func over(a) -> PriorityElement<String.String> {}
/ /... .
let head: PriorityElement<String.Int> = self.head()
head.then(neck())
    .then(lung())
    .then(heart())
    .then(liver())
    .then(over())
// nil also default value()
head.execute()
Copy the code

Google /Promises, MXCL /PromiseKit, RAC, etc. Why not use these frameworks to solve real problems?

There is a point: the framework function is too rich and complex, and I, weak water three thousand I as long as a scoop, the lighter the better principle! Ha ha

Here you can see the detailed design introduction, currently there are OC, Swift, Java three versions of the concrete implementation. Warehouse address: github.com/RunsCode/Pr… Everyone is welcome to correct.

Differentiate AppStore/Adhoc packs in your project (part 2)

Last time, I introduced Configuration, a custom precompiled macro for distinguishing AppStore/Adhoc packages. Later attempts revealed that package types can also be distinguished by in-app profiles (embedded. Mobileprovision) and IAP receipt names.

Embedded. Mobileprovison exists only in non-App Store environments, and it also has an aps-environment parameter that distinguishes between development and production certificates. These two values correspond to the Development and AdHoc packages.

Other IAP in the shelf scenario is sandbox environment (on-line AppStoreConnect TestFlight package is also sandbox environment), whether to pay for the sandbox environment. We can use the Bundle. The main appStoreReceiptURL? LastPathComponent determines whether it is sandboxReceipt.

So using these two things we can distinguish between Development, AdHoc, TestFlight, and AppStore.

Read the embedded mobileprovision

From the command line we can use security to read:

$ security cms -D -i embedded.mobileprovision
Copy the code

Read in the development phase as follows:

struct MobileProvision: Decodable {
    var name: String
    var appIDName: String
    var platform: [String]
    var isXcodeManaged: Bool? = false
    var creationDate: Date
    var expirationDate: Date
    var entitlements: Entitlements
    
    private enum CodingKeys : String.CodingKey {
        case name = "Name"
        case appIDName = "AppIDName"
        case platform = "Platform"
        case isXcodeManaged = "IsXcodeManaged"
        case creationDate = "CreationDate"
        case expirationDate = "ExpirationDate"
        case entitlements = "Entitlements"
    }
    
    // Sublevel: decode entitlements informations
    struct Entitlements: Decodable {
        let keychainAccessGroups: [String]
        let getTaskAllow: Bool
        let apsEnvironment: Environment
        
        private enum CodingKeys: String.CodingKey {
            case keychainAccessGroups = "keychain-access-groups"
            case getTaskAllow = "get-task-allow"
            case apsEnvironment = "aps-environment"
        }
        // Occasionally there will be a disable
        enum Environment: String.Decodable {
            case development, production, disabled
        }
    }
}

class AppEnv {
    
    enum AppCertEnv {
        case devolopment
        case adhoc
        case testflight
        case appstore
    }
    
    var isAppStoreReceiptSandbox: Bool {
        return Bundle.main.appStoreReceiptURL?.lastPathComponent = = "sandboxReceipt"
    }
    
    var embeddedMobileProvisionFile: URL? {
        return Bundle.main.url(forResource: "embedded", withExtension: "mobileprovision")}var appCerEnv: AppCertEnv!
    
    init(a) {
      	// init or other time
        assemblyEnv()
    }
    
    func assemblyEnv(a) {
        if let provision = parseMobileProvision() {
            switch provision.entitlements.apsEnvironment {
            case .development, .disabled:
                appCerEnv = .devolopment
            case .production:
                appCerEnv = .adhoc
            }
        } else {
            if isAppStoreReceiptSandbox {
                appCerEnv = .testflight
            } else {
                appCerEnv = .appstore
            }
        }
    }
    
    /// ref://gist.github.com/perlmunger/8318538a02166ab4c275789a9feb8992
    func parseMobileProvision(a) -> MobileProvision? {
        guard let file = embeddedMobileProvisionFile,
              let string = try? String.init(contentsOf: file, encoding: .isoLatin1) else {
            return nil
        }
        
        // Extract the relevant part of the data string from the start of the opening plist tag to the ending one.
        let scanner = Scanner.init(string: string)
        guard scanner.scanUpTo("<plist", into: nil) ! = false  else {
            return nil
        }
        var extractedPlist: NSString?
        guard scanner.scanUpTo("</plist>", into: &extractedPlist) ! = false else {
            return nil
        }
        
        guard let plist = extractedPlist?.appending("</plist>").data(using: .isoLatin1) else { return nil}
        
        let decoder = PropertyListDecoder(a)do {
            let provision = try decoder.decode(MobileProvision.self, from: plist)
            return provision
        } catch let error {
            // TODO: log / handle error
            print(error.localizedDescription)
            return nil}}}Copy the code

Parsing the interview

Edit: Normal University little Hatten

This section explains isMemberOfClass:, isKindOfClass: two methods related knowledge points.

What is the following print result? (Just to be careful: Person inherits from NSObject)

BOOL res1 = [[NSObject class] isKindOfClass:[NSObject class]].BOOL res2 = [[NSObject class] isMemberOfClass:[NSObject class]].BOOL res3 = [[Person class] isKindOfClass:[Person class]].BOOL res4 = [[Person class] isMemberOfClass:[Person class]].NSLog(@"%d, %d, %d, %d", res1, res2, res3, res4);
Copy the code

Print results: 1, 0, 0, 0

Explanation:

The following are the implementations of the isMemberOfClass:, isKindOfClass: methods and object_getClass() function in objC4-723.

+ (BOOL)isMemberOfClass:(Class)cls {
    return object_getClass((id)self) == cls;
}

- (BOOL)isMemberOfClass:(Class)cls {
    return [self class] == cls;
}

+ (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = object_getClass((id)self); tcls; tcls = tcls->superclass) {
        if (tcls == cls) return YES;
    }
    return NO;
}

- (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
        if (tcls == cls) return YES;
    }
    return NO;
}

Class object_getClass(id obj)
{
    if (obj) return obj->getIsa();
    else return Nil;
}
Copy the code

Emmm sorting out the time found that the later version has done a small optimization, the specific will not expand, but the principle remains the same, the following is the 824 version:

+ (BOOL)isMemberOfClass:(Class)cls {
    return self->ISA() == cls;
}

- (BOOL)isMemberOfClass:(Class)cls {
    return [self class] == cls;
}

+ (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = self->ISA(); tcls; tcls = tcls->getSuperclass()) {
        if (tcls == cls) return YES;
    }
    return NO;
}

- (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = [self class]; tcls; tcls = tcls->getSuperclass()) {
        if (tcls == cls) return YES;
    }
    return NO;
}
Copy the code

From this we can come to the conclusion that:

  • isMemberOfClass:The method is to determine the currentinstance/classThe object’sisaPointing, right?class/meta-classObject type;
  • isKindOfClass:The method is to determine the currentinstance/classThe object’sisaPointing, right?class/meta-classObject or its subclass type.

Obviously isKindOfClass: has a larger scope. If the method caller is an instance object, the passed argument should be a class object. If the method caller is a class object, the passed argument should be a meta-class object. So res2 minus res4 is 0. So why is res1 equal to 1?

Because the ISA of the class of NSObject points to its meta-class object, and the superclass of its meta-class points to its class object, Therefore, [[NSObject class] isKindOfClass:[NSObject class]] holds.

In summary, [instance/class isKindOfClass:[NSObject class]] is always valid. (NSObject and its subclass types, to be careful)

Good blog

King Pilaf is here. I am Big Bear

This topic: Swift Pointers, Swift attribute wrappers

1, Swift pointer uses — from: onevcat

The use of Pointers in Swift is not common, but sometimes we have to try to use Pointers, so it is necessary to have some understanding of Swift’s use of Pointers. This article was written 15 years ago and updated in 2020. This paper makes a mapping between C pointer and Swift pointer application, which is more friendly for students who have some C pointer foundation to read.

5. The 5-Minute Guide to C Pointers

If you are not familiar with C Pointers, it will be difficult to jump directly into Swift’s Pointers.

3, Swift5.1 – Pointer — from HChase

This article gives you a variety of ways to use Swift based on the type of Swift, making it easy to find the usage. For example, how bytes are populated after malloc, how Pointers are created based on address, how types are cast, and so on. If you need to use the Swift pointer in your development, you can refer to the small demo in this article if you are not familiar with it.

4. Set default values for Codable decoding using Property Wrapper — from: onevcat

In Swift, the JSON to Model is Codable, but it is not possible to specify the default value, which requires more redundant code to unblock the option. This article from Onevcat uses the Property Wrapper to set the default value for the Codable decode. In addition, I have summarized it into a file, sscodabledefault.swift, which you are welcome to use.

5, What is a Property Wrapper in Swift — from: sarunw

A property wrapper is a new type that wraps properties to add additional logic. Firstly, the author analyzes how to package attributes before the appearance of attribute wrappers and the problems he encountered. Then, the author uses attribute wrappers to package attributes logically. The author compares the differences between the two methods and briefly describes the benefits of attribute wrappers.

Swift 5 Property Wrappers complete guide — from Nugget: Le Coding

This article is a Chinese tutorial on using property wrappers. It can be read in combination with 4 and 5.

Learning materials

By Mimosa

Machine Learning Crash Course from Google

Address: developers.google.com/machine-lea…

Machine learning tutorial materials from Google, based on the TensorFlow APIs, include video tutorials, real case studies, and hands-on exercises. Thanks to the Google-backed program, you can also go to Kaggle Contest to get real competition experience after you’ve studied, or visit Learn with Google AI to explore a more complete training repository.

ML-For-Beginners from Microsoft

Address: github.com/microsoft/M…

Machine learning tutorial materials from Microsoft. Offers a 12-week, 24-hour course on machine learning. In this course, you will learn classic machine learning, primarily using Scikit-Learn as a library for machine learning. This is covered in our upcoming “AI Beginners” course. These courses can also be used in conjunction with our upcoming “Data Science For Beginners” course. We’re applying some of these classic techniques to data from many parts of the world, so come with us as we travel around the world and learn as we travel! You can also find all the other courses in Microsoft’s repository.

turicreate from Apple

Address: apple. Making. IO/turicreate /…

Turicreate sample model and simplified model program from Apple, it is not a tutorial for learning machine learning, but to provide you with solutions to the task. You can use Turicreate to train simple machine learning models such as recommendation algorithms, object detection, image classification, image similarity, or activity classification. With the resulting.mlModel model, you can put it directly into your project and easily use it with Core ML.

Tools recommended

2. This is the best way to write a book

explainshell

Address: explainshell.com/

This site is similar to regex101, one for parsing regular expressions and one for parsing shell directives. If you don’t often use a shell, you might be confused by a command that has too many parameters and is too long. That’s ok. It will be the main command and each parameter, pass value for a detailed breakdown. For example, this sentence lists all branches that contain 1a1b1c for commit:

git branch -a -v --no-abbrev --contains 1a1b1c
Copy the code

Analytical results:

About us

IOS Fish weekly, mainly share the experience and lessons encountered in the development process, quality blogs, high-quality learning materials, practical development tools, etc. The weekly warehouse is here: github.com/zhangferry/… If you have a good recommendation you can submit it as an issue. You can also apply to be our resident editor and help maintain the weekly. In addition, you can pay attention to the public number: the road of iOS growth, the background click into the group communication, contact us, get more content.

Phase to recommend

IOS Fish Weekly issue 22

IOS Fish Weekly issue 21

IOS Fish Weekly issue 20

The 19th issue of iOS Fish Week