Skip to content

Commit

Permalink
Merge commit '6965fe817fe14075b66413ba27e7072c60d699d9' into feature/F…
Browse files Browse the repository at this point in the history
…EM-831-Changes

* commit '6965fe817fe14075b66413ba27e7072c60d699d9': (65 commits)
  Simple OVP Session Provider (#90)
  #FEM-1117 (#88)
  #FEC-6462 #comment [~oren.melamed], do we know this issue doesn’t happen for Phoenix too? If you could get me a response sample for concurrency I could check. (#87)
  Added initObj key to the media mark request. It was missing. (#84)
  fix podspec
  Fec 6473 (#86)
  Small enhancement to player config (#82)
  Fixes memory leak created by Apple’s interoperability (#85)
  Update README.md
  Fix to prevent initializing `PlayKitManager` from outside in swift and objc (#81)
  Some tweaks for objective-c compatibility (#80)
  fixed issue with `KalturaLiveStatsPlugin` conforming to PKPlugin (#79)
  support wideinve privae pod
  Config API change and PKPlugin (#78)
  LocalAssetsManager: rename registerDownloadedAsset to assetDownloadFinished. (#77)
  bump v0.1.9
  fix event observation on KalturaLiveStatsPlugin
  fix issues with tests after events change. (#74)
  bump v0.1.8
  update podfile
  ...

# Conflicts:
#	Example/PlayKit.xcodeproj/project.pbxproj
#	Example/Podfile
#	Example/Podfile.lock
#	Example/Tests/MediaEntryProvider/OVPMediaProviederTest.swift
  • Loading branch information
srivkas committed Feb 19, 2017
2 parents 6220658 + 6965fe8 commit 4da466a
Show file tree
Hide file tree
Showing 67 changed files with 1,879 additions and 1,068 deletions.
1 change: 1 addition & 0 deletions .swift-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.0
1 change: 1 addition & 0 deletions .swift_version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.0
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ before_install:
- gem install cocoapods # Since Travis is not always on latest version
script:
- cd PlayKitFramework
- pod install
- pod update
- xcodebuild -scheme PlayKitFramework -workspace PlayKitFramework.xcworkspace
notifications:
email:
Expand Down
70 changes: 70 additions & 0 deletions Classes/Managers/AppState/AppStateProvider.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//
// AppStateProvider.swift
// Pods
//
// Created by Gal Orlanczyk on 19/01/2017.
//
//

import Foundation

/// The delegate of `AppStateProvider`, allows the delegate to inform on app state notifications.
protocol AppStateProviderDelegate: class {
/// fire this delegate function when received observation event.
/// for every observer with the same observation event process the on observe block.
func appStateEventPosted(name: ObservationName)
}

/// The interface of `AppStateProvider`, allows us to better divide the logic and mock easier.
protocol AppStateProviderProtocol {
var notificationsManager: NotificationsManager { get }
/// Holds all the observation names we will be observing.
/// If you want to observe more events add them here.
var observationNames: Set<ObservationName> { get }
weak var delegate: AppStateProviderDelegate? { get }
}

extension AppStateProviderProtocol {
/// Add observers for the provided notification names.
func addObservers() {
observationNames.forEach { name in
notificationsManager.addObserver(notificationName: name) { notification in
self.delegate?.appStateEventPosted(name: notification.name)
}
}
}

/// Remove observers for the provided notification names.
func removeObservers() {
notificationsManager.removeAllObservers()
}

}

/************************************************************/
// MARK: - AppStateProvider
/************************************************************/

/// The `AppStateProvider` is a provider for receiving events from the system about app states.
/// Used to seperate the events providing from the app state subject and enabling us to mock better.
final class AppStateProvider: AppStateProviderProtocol {

init(delegate: AppStateProviderDelegate? = nil) {
self.delegate = delegate
}

var delegate: AppStateProviderDelegate?

let notificationsManager = NotificationsManager()

let observationNames: Set<ObservationName> = [
.UIApplicationWillTerminate,
.UIApplicationDidEnterBackground,
.UIApplicationDidBecomeActive,
.UIApplicationWillResignActive,
.UIApplicationWillEnterForeground
]

}


168 changes: 168 additions & 0 deletions Classes/Managers/AppState/AppStateSubject.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
//
// AppStateSubject.swift
// Pods
//
// Created by Gal Orlanczyk on 19/01/2017.
//
//

import Foundation

/// The interface of `AppStateSubject`, allows us to better divide the logic and mock easier.
protocol AppStateSubjectProtocol: class, AppStateProviderDelegate {
associatedtype InstanceType
static var sharedInstance: InstanceType { get }
/// Lock object for synchronizing access.
var lock: AnyObject { get }
/// The app state events provider.
var appStateProvider: AppStateProvider { get }
/// The current app state observers.
var observers: [AppStateObservable] { get set }
/// States whether currently observing.
/// - note: when mocking set initial value to false.
var isObserving: Bool { get set }
}

extension AppStateSubjectProtocol {
/// Starts observing the app state events
func startObservingAppState() {
sync {
// if not already observing and has more than 0 oberserver then start observing
if !isObserving {
PKLog.trace("start observing app state")
appStateProvider.addObservers()
isObserving = true
}
}
}

/// Stops observing the app state events.
func stopObservingAppState() {
sync {
if isObserving {
PKLog.trace("stop observing app state")
appStateProvider.removeObservers()
isObserving = false
}
}
}

/// Adds an observer to inform when state events are posted.
func add(observer: AppStateObservable) {
sync {
PKLog.trace("add observer, \(observer)")
// if no observers were available start observing now
if observers.count == 0 && !isObserving {
startObservingAppState()
}
observers.append(observer)
}
}

/// Removes an observer to stop being inform when state events are posted.
func remove(observer: AppStateObservable) {
sync {
for i in 0..<observers.count {
if observers[i] === observer {
let removedObserver = observers.remove(at: i)
PKLog.trace("removed observer, \(removedObserver)")
// if no more observers available stop observing
if observers.count == 0 && isObserving {
stopObservingAppState()
}
break
}
}
}
}

/// Removes all observers and stop observing.
func removeAllObservers() {
sync {
if observers.count > 0 {
PKLog.trace("remove all observers")
observers.removeAll()
stopObservingAppState()
}
}
}

/************************************************************/
// MARK: AppStateProviderDelegate
/************************************************************/

func appStateEventPosted(name: ObservationName) {
sync {
PKLog.trace("app state event posted with name: \(name.rawValue)")
for observer in self.observers {
let filteredObservations = observer.observations.filter { $0.name == name }
for observation in filteredObservations {
observation.onObserve()
}
}
}
}

// MARK: Private
/// synchornized function
private func sync(block: () -> ()) {
objc_sync_enter(lock)
block()
objc_sync_exit(lock)
}

}

/************************************************************/
// MARK: - AppStateSubject
/************************************************************/

/// The `AppStateSubject` class provides a way to add/remove application state observers.
///
/// - note: Subject is a class that is both observing and being observered.
/// In our case listening to events using the provider and posting using the obervations onObserve.
///
/// **For Unit-Testing:** When mocking this object just conform to the `AppStateSubjectProtocol`.
/// For firing events to observers manually use `appStateEventPosted(name: ObservationName)` with the observation name.
final class AppStateSubject: AppStateSubjectProtocol {

// singleton object and private init to prevent unwanted creation of more objects.
static let sharedInstance = AppStateSubject()
private init() {
self.appStateProvider = AppStateProvider()
self.appStateProvider.delegate = self
}

let lock: AnyObject = UUID().uuidString as AnyObject

var observers = [AppStateObservable]()
var appStateProvider: AppStateProvider
var isObserving = false
}

/************************************************************/
// MARK: - Types
/************************************************************/

/// Used to specify observation name
typealias ObservationName = Notification.Name // used as typealias in case we will change type in the future.

/// represents a single observation with observation name as the type, and a block to perform when observing.
struct NotificationObservation: Hashable {
var name: ObservationName
var onObserve: () -> Void

var hashValue: Int {
return name.rawValue.hash
}
}

func == (lhs: NotificationObservation, rhs: NotificationObservation) -> Bool {
return lhs.name.rawValue == rhs.name.rawValue
}

/// A type that provides a set of NotificationObservation to observe.
/// This interface defines the observations we would want in our class, for example a set of [willTerminate, didEnterBackground etc.]
protocol AppStateObservable: AnyObject {
var observations: Set<NotificationObservation> { get }
}

0 comments on commit 4da466a

Please sign in to comment.