background

As you blog more and more, it’s inevitable that you’ll have to insert images to illustrate.

Figure bed choice

First of all, I investigated the map bed service on the market. In line with the goal of stability and long-term, I filtered out the small pheasant website that played a gun to change a place. The remaining reliable advantages and disadvantages are as follows.

Figure bed advantages disadvantages
Tencent cloud Free domain name There may be charges in the future
Seven cattle free Domain name and registration required
And take the cloud Free domain name There may be charges in the future
Ali cloud At present most complete Charge for domain name
weibo Free domain name Unstable anonymous upload

As a small blog starting up, you should pay more attention to content, and then consider domain name registration or large data plan, so try to choose free chart bed. Is really poor

As one of the largest traffic users in China, Weibo certainly has no problem with the CDN and quality of its picture bed. However, uploaded pictures will have their own watermarks, and anonymous uploading always feels unreliable.

There are still two options left, and paiyun entered the object storage field earlier and more mature than Tencent Cloud, but in terms of scale and technology, I still prefer to believe Tencent.

tool

After registering Tencent cloud account, the next problem is how to combine Chart bed and MarkDown more conveniently to improve efficiency and experience.

IPic perfectly meets my needs, this is a Mac status bar software, support to upload local pictures to the set graph bed, after obtaining the picture address according to! [](URL) format copy to clipboard.

So why not use a good app?

Because I don’t want to pay yearly. The default application is weibo map bed, if you want to use other map bed you need to buy professional version, 60 yuan per year. If it is a buyout, also bought, annual fee in the heart always have a knot in one’s heart affectation.

Suddenly, IT hit me! Develop your own! Idle egg hurts

Having worked on iPhone apps for years and never developed a status bar for the Mac, it was a good time to exercise Swift, so I went ahead. Unexpectedly, it took a month to develop


Demand for design

The logic of the product is basically the same as that of iPic. Based on the status bar, PNG and JPG files are selected to upload.

You can set whether to compress the picture or not, and the compression will be below 500K.

There also needs to be a login interface to record Tencent cloud account and repository information.

After the file is successfully uploaded, a notification is displayed and the file is copied to the clipboard.

If you accidentally copy another text and lose the link, click the notification again to retrieve it.


Problems encountered

Swift

The first level is the programming language.

Although I have learned Swift systematically, I still cannot change my way of thinking due to years of using Objective-C development.

Strictly null variable

The obvious difference is the way empty variables are handled.

In ObjC, pointer variables can be nil (i.e., 0), and nothing happens when you perform a method on nil, so it’s partially safe.

Swift is stricter with empty variables. The modifier variable must have a specific value,? Modified variables have the possibility of having empty values.

Nil is no longer represented as an empty object, but as a null value, and calling a method to a null value causes a flash back. To treat? Modifier variables must be used carefully, and it is best to determine whether they have values before using them. Fortunately, syntactic sugar can solve these problems.

// Defaults to nil
var money : String?
// The variable has a value
money = "million"

// Check the value before using it
ifmoney ! =nil {
    print("I have \(money!) dollars.")}// execute after ensuring that the variable has a value and assigning it to the security variable
if let account = money {
    print("I have \(account) dollars.")}// If the variable has no value, an else event is executed and return is returned
guard let account = money else {
    print("I have no money.")}print("I have \(account) dollars.") 
Copy the code

Fair use! ? It makes our code safer and cleaner.

Nil for Swift is not the same as nil in Objective-C. In Objective-C, nil is a pointer to an object that doesn’t exist. In Swift, nil is not a pointer — it is a definite value used to indicate that a value is missing. Any type of optional state can be set to nil, not just object types.

Throw a warning

ObjC has the use of @throw, but according to Apple’s official description, it is expensive to implement. The reason is that ObjC is based on C rather than C++, so it can only be implemented using setjmp() and Longjmp () methods, which can cause memory leaks.

Important: Exceptions are resource-intensive in Objective-C. You should not use exceptions for general flow-control, or simply to signify errors (such as a file not being accessible)

Swift addresses this problem at its root and optimizes the entire process with enumerations.

enum CompressError : Error {
    case NoImage
    case OverSize(size : Int)}func compressImage(_ imageData: Data?) throws -> Data? {
        guard var compressData = imageData else {
            throw CompressError.NoImage
        }

        if compressData.count > maxSize {
            throw CompressError.OverSize(size: compressData.count)}}func uploadImage(_ imageData: Data?) {
    var compressData : Data? = nil
    do {
        compressData = try self.compressImage(imageData)
    } catch CompressError.NoImage {
        print("Image Not Exist")}catch CompressError.OverSize(let size) {
        print("Image over size of \(size)")}catch _ {}

    // In a concise way, ignore the processing warnings
    let compressData = try? self.compressImage(imageData)
}

Copy the code

Swift’s powerful enumerated types allow you to customize warnings to deliver the information you need, making the process smoother.

The syntax also supports try? Ignore the warnings and get a variable that may be null. If you are confident that you will never throw an exception, you can use try! Gets an affirmative value.

Mac OS development

In the process of actually writing Cocoa code, I found that it was quite different from UIKit.

The control logic

The level of UIKit is usually UINavigationController -> UIViewController

Cocoa has a different level, NSWindowController -> NSViewController

The reason is also very simple, there is usually only one window on the phone, relying on the navigation bar to jump to the page. On the desktop side, however, the logic is different. New pages are usually displayed as new Windows.

The desktop side has a specific status bar control, NSMenu, in which to manipulate menu items is also a new challenge.

Tencent Cloud

Since Tencent Cloud only provides iOS library, I need to readjust the library file to Cocoa code first. This part is also a bit of a pain, removing device-specific code and applications, notifications to and from the background, and handling conversions to similar functions (such as UIImage -> NSImage).

At the same time, there is a second pit, Tencent cloud library is ObjC code, so it needs to be mixed.

Add the Targets/Build Phases/Embed Frameworks to the Targets/Build Phases/Embed Frameworks in the main project.

Next, create the project-bridge-header. h Header file in the Swift Project, where you reference the SDK libraries.

Finally, set the Targets/Build Settings/Objective-c Bridging Header files to solve the code mixing problem.

The principle is to automatically create a PCH based on a header file, and the ObjC code referenced in the header file is bridge to the project.

Image compression algorithm

Another reason for not using off-the-shelf software is that I want to control the parameters and effects of compressed images myself.

After investigating and experimenting with the compression effect of pictures, I finally chose to compress them into JPG format, with a size limit of 500K, compression ratio of 0.75 minimum and ratio width of 1280px.

The first picture of the beautiful woman, the initial is 1.9m 5087×3661, due to the large size, after the first compression of the picture quality, the capacity increased to 2.4m.

Shrink the aspect ratio to 1280×922 and the image becomes larger again, this time to 4.7m. (Changing width and height requires creating a new canvas, which must have alpha channels and other Settings, so it will be larger)

We then compressed the image to 260K at a compression rate of 0.9, successfully achieving our goal.


conclusion

It has been two months since my last blog, partly due to some changes in my life and partly due to my unfamiliarity with Cocoa + Swift development.

The Github project is now open source. Welcome to comment and ridicule.

The biggest takeaway from this project was getting out of your comfort zone. Human nature involves inertia, a tendency to do familiar work in familiar territory. But just like businesses, it’s either innovation or death. Technology is constantly evolving, and if it doesn’t keep up, it will eventually become obsolete. With this mutual encouragement!


The resources

Swift 4.0 tutorial

App picture compression cutting principle and upload scheme