Writing this was much simpler because I was able to look at other people plugins, mostly those related to console, without them being open sourcing it would be more work to figure this stuff out with hopper.
Open source helps us move forward, learn and share together
Open source softwares are in fact intellectual properties, and the authors should get acknowledgement for the work that they do.
It’s not fair to take the credit of other’s work and not giving any attribution
By its nature, open source software has a unique relationship with intellectual property rights
One thing that’s not up for debate in most circles is that it’s dishonest and disingenuous to take someone else’s project, modify it slightly, and call it your own.
Further, regardless of whether or not a project crosses that line, it must (by the terms of most open source licenses) acknowledge the original work/author.
And the reaction
Attribute Original Author
DMCA takedown on repos that rip off Async
It’s always sad to see blatant plagiarism, and I think it really hurts the community more than the author itself. It gives people a good reason to keep the sources private.
Being nice
I often hear people say that
It is easier to find good developer than developer with good attitude
Whether it is hot vs cold, Signal vs Signal Producer, Observable vs Enumerable, … it’s good to understand how it gets implemented, so that to have a good sense of how they work
Monad
Understanding Monad
Basically, Signal and its Result are just monads, which are thing that can be mapped and chained.
Signal makes use of deferred execution callback blocks, and push vs pull is just how the Signal updates its value and the order the callbacks are called
Execution callback block is that we pass a function to another function, and it will get called when appropriated
Sync vs Async
Monad can be in either sync or async mode. Sync is easier to understand, but async is somewhat you’re already familiar and used in practice
Basically,
Sync: you get the returned value right away via return
Aync: you get the returned value via callback block
Here is an example of a simple function
1 2 3 4 5 6 7 8 9 10 11 12
// Sync func sum(a: Int, b: Int) -> Int { return a + b }
// Async func sum(a: Int, b: Int, completion: Int -> Void) { // Assumed it is a very long task to get the result let result = a + b
// Sync public func map(@noescape f: T -> U) -> Event { switch self { case let .Next(value): return .Next(value: f(value)) case let .Failed(error): return .Failed(error: error) } }
// Async public func map(f: (T, U -> Void) -> Void) -> ((Event -> Void) -> Void) { return { g in // g: Event -> Void switch self { case let .Next(value): f(value) { transformedValue in // transformedValue: U g(.Next(value: transformedValue)) } case let .Failed(error): g(.Failed(error: error)) } } }
Push Signal
Signal.swift
Take a look at my Push Signal, called Signal, it is like how Promise A+ Then works
public func subscribe(f: Event -> Void) -> Signal { // Callback if let event = event { f(event) }
callbacks.append(f)
return self }
public func map(f: T -> U) -> Signal { let signal = Signal()
subscribe { event in signal.update(event: event.map(f)) }
return signal } }
Usage
1 2 3 4 5 6 7 8 9 10 11 12 13
let signal = Signal()
signal.map { value in return value.characters.count }.subscribe { event in if case let .Next(value) = event { XCTAssert(value == 4) } else { XCTAssert(false) } }
signal.sendNext("test")
Callbacks
Given a chained signals like this
A -(map)-> B -(flatMap)-> C -(flatMap)-> D -(subscribe)
The idea is we send event to the source signal, and it propagates events through via callbacks.
Triggered by sending event to the source signal.
We must keep A as it keeps the others around
We subscribe the last D
We send event to the first A
A ‘s callback gets called, it it in turn calls callback of B with the result of A ‘s map, then B ‘s callback calls C ‘s callback with the result of B
‘s flatMap, …
Pull Signal
Future.swift
Take a look at my Pull Signal, called Future
Implementation
Here operation is a task, when called and completed, will notify its completion
public func start(completion: Event -> Void) { operation() { event in completion(event) } }
public func map(f: T -> U) -> Future { return Future { completion in self.start { event in completion(event.map(f)) } } } }
Usage
1 2 3 4 5 6 7 8 9 10 11 12 13
let _ = Future { completion in // There is some work here completion(Event(value: "test")) } .map { value in value.characters.count }.start { event in if case let .Next(value) = event { XCTAssert(value == 4) } else { XCTAssert(false) } }
Callbacks
Given a chained signals like this
A -(map)-> B -(flatMap)-> C -(flatMap)-> D -(subscribe)
The idea is we subscribe to the final signal D, and it cause the previous signals to action.
Triggered by subscribing to the final signal.
We must keep D as it keeps the others around
We subscribe the last D
D ‘s operation actions, and it cause C ‘s operation to action, … then A ‘s operation actions. It is in A that the task is performed (like fetching network, retrieving database, file access, heavy computation, …) to get the result, and A ‘s completion gets called. Then A’s completion calls B ‘s completion with the result mapped by B ‘s map, … all the way to the subscriber ‘s completion block
Haskell is notorious for currying, and Swift has currying, too
I love ReactiveCocoa, RxSwift and I always take time to dig into it. The other day, I was practise making Signal based on this talk
Take a look at my repo Signal
filter
I was making a filter for a Signal. The idea of filter is that we should update signal if the Event is Next with right filtered value
Signal.swift
1 2 3 4 5 6 7 8 9 10 11 12 13
public func filter(f: T -> Bool) -> Signal{ let signal = Signal() subscribe { result in switch(result) { case let .Success(value): if f(value) { signal.update(result) } case let .Error(error): signal.update(.Error(error)) } } return signal }
2 params
But having Event as another monad, I think it should be more encapsulated if that switching logic gets moved into the Event. Here the filter takes 2 params
Event.swift
1 2 3 4 5 6 7 8 9 10
func filter(f: T -> Bool, callback: (Event -> Void)) { switch self { case let .Next(value) where f(value): callback(self) case .Failed: callback(self) default: break } }
Signal.swift
1 2 3 4 5 6 7 8 9
public func filter(f: T -> Bool) -> Signal { let signal = Signal()
subscribe { event in event.filter(f, callback: signal.update) }
return signal }
Currying
With currying, we can make filter a more abstract function, and defer the decision to pass the callback param. It is a little carried away but I find it helpful this way
Now filter accepts 1 param, and it returns a function that takes callback as its param
Event.swift
1 2 3 4 5 6 7 8 9 10 11 12
func filter(f: T -> Bool) -> ((Event -> Void) -> Void) { return { g in switch self { case let .Next(value) where f(value): g(self) case .Failed: g(self) default: break } } }
Signal.swift
1 2 3 4 5 6 7 8 9
public func filter(f: T -> Bool) -> Signal { let signal = Signal()
subscribe { event in event.filter(f)(signal.update) }
return signal }
Curry syntax in Swift 2
Swift 2 supports curry syntax function
1 2 3 4 5 6 7
funcsum(a: Int)(b: Int) -> Int { return a + b }
let sumWith5 = sum(5) let result = sumWith5(b: 10)
NSNotificationCenter is like central hub where notifications are posted and received by any parts of the app
Registering
Registering for notification n times, you get notified n times
debugDescription
As of iOS 9+,
NSNotificationCenter and NSDistributedNotificationCenter will now provide a debug description when printing from the debugger that will list all registered observers including references that have been zeroed out for aiding in debugging notification registrations. This data is only valid per the duration of the breakpoint since the underlying store must account for multithreaded environments. Wildcard registrations for notifications where the name or object that was passed to the addObserver method family was null will be printed in the debug description as *.
NSNotificationCenter holds weak reference to its observer
Regular notification centers deliver notifications on the thread in which the notification was posted
addObserverForName(_:object:queue:usingBlock:)
Adds an entry to the receiver’s dispatch table with a notification queue and a block to add to the queue, and optional criteria: notification name and sender.
Before an object that is observing notifications is deallocated, it must tell the notification center to stop sending it notifications. Otherwise, the next notification gets sent to a nonexistent object and the program crashes
In OS X 10.11 and iOS 9.0 NSNotificationCenter and NSDistributedNotificationCenter will no longer send notifications to registered observers that may be deallocated
This means that observers are not required to un-register in their deallocation method
However,
Block based observers via the -[NSNotificationCenter addObserverForName:object:queue:usingBlock] method still need to be un-registered when no longer in use since the system still holds a strong reference to these observers
So we must call removeObserver on the returned observer object
A notification center delivers notifications to observers synchronously. In other words, when posting a notification, control does not return to the poster until all observers have received and processed the notification
If you have performance problem of posting notifications to large number of observers, consider using
dispatch_after
Many NSNotificationCenter
NSNotificationQueue
NSNotificationQueue
Enqueuing methods return immediately
Associated with the run loop modes
There ‘s defaultQueue for the current thread
1 2 3
let queue = NSNotificationQueue(notificationCenter: NSNotificationCenter.defaultCenter()) let notification = NSNotification(name: "CacheDidUpdateNotification", object: self) queue.enqueueNotification(notification, postingStyle: .PostASAP)
Christmas is when we I have the most special feeling. The cool air, the snow, the reunion, the church bell ringing, …
(From google)
It ‘s beginning to look a lot like Christmas. First with Xcode
Xmas
Xmas is an Xcode plugin that shows Xmas picture along with wishing message whenever a build succeeds
How it works
Swift
Try to do much of the job in Swift as possible
DVTKit
Xcode uses DVTBezelAlertPanel to display alert. So we swizzle its initWithIcon:message:parentWindow:duration:
DVTBezelAlertPanel is from DVTKit. I thought about importing run time header and just extension it. But I find swizzling in Objective C a much more easier solution
NSVisualEffectView
It seems that NSImage added to the panel ‘s NSVisualEffectView had it template set to YES again, hence causing the image into template color with the panel background color
This happens in the init method. So we must change template back to NO after init happens
structHankPym{ let suit = AntManSuit(name: "Ant Man ID #101")
funcfight() { print("Fighting with the suit named " + suit.name) } }
let hankPym = HankPym() hankPym.fight()
Everytime HankPym is created, he always uses the Ant Man suit. This time he is so coupled to the role Ant Man
More suits
Well, he does not have to be too dependent on the Ant Man suit. We know Hank Pym is a genius scientist, he has more suits to use. Let’s make it decoupled
funcfight() { print("Fighting with the suit named " + suit.name) } }
let suit = YellowJacketSuit(name: "Yellow Jacket ID #33") let hankPym = HankPym(suit: suit) hankPym.fight()
Now Hank Pym can be more flexible on which suit to use.
Dependency Injection
The technique we just saw is called Dependency Injection, in which Hank Pym does not need to create the Suit, it will be provided through constructor or property.
Dependency Inversion Principle
In the first example, Hank Pym is dependent on the concrete implementation of the Suit
In the second example, both Hank Pym and the suits are dependent on the Suit protocol. This way Hank Pym only knows about the Suit protocol, and future suits must be crafted to that it conforms to the Suit protocol
This way the dependency is inverted
High level modules should not depend upon low level modules. Both should depend upon abstractions.
What is the high level policy? It is the abstractions that underlie the application, the
truths that do not vary when the details are changed
For example, in an old school menu, you might have:
1 2 3 4 5 6
print "enter your name" read name print "enter your address" read address etc... store in database
thereby controlling the flow of user interaction.
In a GUI program or some such, instead we say
1 2 3
when the user types in field a, store it in NAME when the user types in field b, store it in ADDRESS when the user clicks the save button, call StoreInDatabase
You how have a brief understanding of how IoC means
IoC container
In the 2nd example of the Suit protocol, you can see how there is a inversion of control. What if there is a container that contains all the Suit conformances?
In C, the sizeof operator returns the size of any variable or data type. In Swift, you use the sizeof function to get the size of a given type, or the sizeofValue function to get the size of the type of a given value
When developing iOS apps, most of the libraries I use are on MIT licenses, a permissive license, which is good :]
MIT vs GPL vs Apache
These have many things in common
Commercial Use: This software and derivatives may be used for commercial purposes.
Distribution: You may distribute this software.
Modification: This software may be modified.
Private use: You may use and modify the software without distributing it.
License and copyright notice: Include a copy of the license and copyright notice with the code.
But
GPL is Disclose Source: copyleft license that requires anyone who distributes your code or a derivative work to make the source available under the same terms.
Apache is Patent Grant and State Changes: Indicate significant changes made to the code
MIT is simple, permissive. You can do anything you like