Comment on page
FAQ & Troubleshooting
This section contains common mistakes that can lead to a
FeedViewController
to not behave correctly.Properly managing a view controller's lifecycle is easily overlooked because Xcode does not strictly enforce this. So when a subtle issue does arise the root cause may not be all that obvious and is hard to debug.
When add a view controller as a child of another view controller it is important to call the correct methods so that it will start to receive the normal view controller life cycle events.
The steps for attaching a child view controller are
- 1.Add child to parent view controller
- 2.Add add root view from child view controller to some view in the parent view controller
- 3.Set constraints on child view controller view
- 4.Inform the child view controller that it has been moved onto the parent view controller
The last step is really important and also overlooked as it will inform the child view controller that it that it can begin laying out its components.
Here is an example
let feedVC = //...
parentViewController.addChild(feedVC)
parentViewController.view.addSubView(feedVC.view)
feedVC.view.translatesAutoresizingMaskIntoConstraints = false
// ... Set feed constraint
NSLayoutConstraint.activate(
constraints
)
feedVC.didMove(toParent: parentViewController)
Similar to attaching a view controller we must also detach a view controller. Detaching is more straightforeward.
The steps to detach
- 1.Inform the child view controller it will be moving from the parent view controller
- 2.Remove the child view controller from the parent
- 3.remove the child view controller view from super view
feedVC.willMove(toParent: nil) // Let's the child VC know it will be detached from the parent
feedVC.removeFromParent()
feedVC.view.removeSuperview()
Often times it is desirable to display a horizontal scrolling feed within a UITableView or UICollectionView.
There are two lifecycle events on the UITableView and UICollectionView that we can use to attach and deatch the FeedViewController. For details on attaching and detaching see View Controller Lifecycle Management section above.
The Table and Collection views have a delegate method that is called before a cell is going to be shown on a screen; table/collectionView(_:willDisplayCell:at:). When this method is called it is a good time to attach the feed view controller.
Conversely, the Table and Collection views have a method that is called just after a cell has left the screen; table/collectionView(_:didEndDisplayingCell:at:). WHen this method is called it is a good time to detach the feed view controller.
Because the
VideoFeedViewController
is self contained it must be able to avoid safe areas. As such the VideoFeedViewController
attaches its child view controller to the safeAreaGuide
of its view.There are some scenarios that may cause odd behaviors when the
VideoFeedViewController
is laid out.This scenario occurs when a the
VideoFeedViewController
is attached to a UIScrollView
, UICollectionView
or UITableView
which has a sibling view. The safe area guides will propagate down to the VideoFeedViewController
when the UIScrollView
, UICollectionView
or UITableView
is not the first child in the view hierarchy.Typically,
UIScrollView
, UICollectionView
or UITableView
respects the safe area by adjusting the content size to allow the content to scroll above the safe area. Thus, UIKit does not pass the guides down into views that are within the content view of the UIScrollView
. However, behavior suggests there is a bug within the UIKit logic.To get around this issue simply make sure the
UIScrollView
, UICollectionView
or UITableView
is the first sibling of the parent view. In story board simply drag the view in question to the top of the subclasses. Or, if you are building views programmatically simply make sure to view.addSubview()
the view in question first.FireworkVideoSDK.initializeSDK
accepts an optional delegate
parameter that can receive any errors the SDK outputs during setup. This delegate can be any class that conforms to the FireworkVideoSDKDelegate
protocol. See example code below that uses AppDelegate
to print any errors to console.import UIKit
/// Add the dependency SDK
import FireworkVideo
@main
class AppDelegate: UIResponder, UIApplicationDelegate, FireworkVideoSDKDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FireworkVideoSDK.initializeSDK(delegate: self)
return true
}
func fireworkVideoDidLoadSuccessfully() {
print("FireworkVideo loaded successfully.")
}
func fireworkVideoDidLoadWith(error: FireworkVideoSDKError) {
switch error {
case .missingAppID:
print("FireworkVideo loaded with error due to missing FireworkVideo app ID.")
case .authenticationFailure:
print("FireworkVideo loaded with error due to authentication failure.")
@unknown default:
break
}
}
VideoFeedViewController
exposes an optional delegate
property that can receive any errors the SDK outputs when loading the video feed or a success when the video feed loaded successfully./// Add the dependency SDK
import FireworkVideo
class VideoFeedService: VideoFeedViewControllerDelegate {
func videoFeedDidLoadFeed(_ viewController: FireworkVideo.VideoFeedViewController) {
print("Video feed on view controller \(viewController) loaded.")
}
func videoFeed(_ viewController: FireworkVideo.VideoFeedViewController, didFailToLoadFeed error: FireworkVideo.VideoFeedError) {
if case let FireworkVideo.VideoFeedError.contentSourceError(contentSourceError) = error {
print("Video feed on view controller \(viewController) loaded with error \(contentSourceError.errorDescription).")
} else if case let FireworkVideo.VideoFeedError.unknownError(underlyingError) = error {
print("Video feed on view controller \(viewController) loaded with error \(underlyingError.localizedDescription).")
}
}
}
In the event the feed is empty or the SDK encounters an error when downloading videos, create a new instance and replace the existing instance in your view hierarchy. If the video feed source configured for the view controller does not have videos available, you may need to supply an alternative source when creating the new instance.
If
VideoFeedViewController
is a child view controller, make sure to call the view controller containment lifecycle methods when removing it from your apps view hierarchy to ensure proper cleanup./// Removing videoFeedViewController from it's parent view controller
videoFeedViewController.willMove(toParent: nil)
videoFeedViewController.view.removeFromSuperview()
videoFeedViewController.removeFromParent()
A commonly asked question is how to create video feed with circular thumbnails. You can use the following logic to implement this
You can create a circular thumbnails by setting the
cornerRadius
property in viewConfiguration
of a VideoFeedViewController
.Note: This would only work when the number of lines is fixed. This can be done on theVideoFeedItemContentConfiguration.title.numberOfLines
The following properties are needed identify the corner radius required for circular thumbnails.
- 1.
totalHeight
= This will be the height you set for the VideoFeedViewController - 2.
contentPadding
= This value is found in thelayout.contentInsets
property of the VideoFeedViewController - 3.
labelHeight
= The size of the font used on theviewConfiguration.itemView.title.font
- 4.
titleSpacing
= The spacing between the label and the thumbnail. This is located in theviewConfiguration.itemView.titleLayoutConfiguration.insets.top
Putting it all together
imageSize = totalHeight - (contentPadding.top + contentPadding.bottom) + (labelHeight * numberOfLines) + titleSpacing
cornerRadius = imageSize / 2
Now set the
cornerRaidus
property for your viewConfiguration
and you are done!