Using Multiple libraries for a single ViewController/UIcollectionView - ios

first of all sorry for that Question Title you can just read on to know my problem. I am a bit confused about adding multiple libraries that points to a single view controller. So the situation is I have a ViewController where I need a SideMenu and a Drag and Drop Functionality. The ViewController have UICollectionView with Images in it that can be used to drag and Drop in between the images itself and Need a SideMenu that the user can Swipe to navigate to find Menu Items. For SideMenu I have Tried this library SSASideMenu
and for Drag and Drop I used DragDropCollectionView
when I use one library at a time I can make it work but when i use both I get this error at this line
to use SSASidemenu we need some code in AppDelegate File
window = UIWindow(frame: UIScreen.mainScreen().bounds)
// MARK : Setup SSASideMenu
let sideMenu = SSASideMenu(contentViewController: UINavigationController(rootViewController: HomeViewController()), leftMenuViewController: LeftMenuViewController(), rightMenuViewController: RightMenuViewController())
sideMenu.backgroundImage = UIImage(named: "Background.jpg")
sideMenu.configure(SSASideMenu.MenuViewEffect(fade: true, scale: true, scaleBackground: false))
sideMenu.configure(SSASideMenu.ContentViewEffect(alpha: 1.0, scale: 0.7))
sideMenu.configure(SSASideMenu.ContentViewShadow(enabled: true, color: UIColor.blackColor(), opacity: 0.6, radius: 6.0))
sideMenu.delegate = self
window?.rootViewController = sideMenu
window?.makeKeyAndVisible()
inside didFinishLaunchingWithOptions
but when I comment this code in appdelegate the Dragdrop works great.
So my question Is, is it possible to add multiple libraries in a single ViewController ? if so what's going wrong with my method? Can I achieve both the functionality in a same viewcontroller ?
Created a Sample Project with both The Libraries Mentioned in my question. Can get it HERE
Comment the line in Appdelegate and The DragandDropCollectionview works fine and if not error occurs

As explained in DragDropCollectionView example , you must configure your class where you have viewDidLoad (like your picture as showed), otherwise you cannot set delegate:
class ViewController: ...(your class type), DrapDropCollectionViewDelegate {
}

Related

childViewControllers is empty after calling addChildViewController

I have a question regarding add/remove childviewcontrollers with ContainerView.
I have a UIViewController named "ContainerViewController" that contains a ContainerView, and this ContainerView has a UIViewController named "ContainerLinkViewController". I also have four other UIViewControllers that will be added to or removed from this "ContainerLinkViewController" whenever user a clicks one of the tab button that is placed at the bottom of "ContainerViewController". The storyboard looks like below.
NOTE that the custom segues connected to those four UiViewcontrollers are just empty segue that does nothing but show visual connection in storyboard.
So what I do is first add the First Tab ViewController to "ContainerLinkViewController" as a childViewController by using below code in viewDidLoad().
let firstTabViewController = self.storyboard?.instantiateViewController(withIdentifier: "FirstTabViewController") as! FirstTabViewController
self.addChildViewController(firstTabViewController)
firstTabViewController.view.frame = self.view.bounds
self.view.addSubview(firstTabViewController.view)
firstTabViewController.didMove(toParentViewController: self)
After this initial setup, whenever user tabs on one of those tab buttons, I send signal from "ContainerViewController" that which UIViewController is to be added as new childViewController to "ContainerLinkViewController" and switching the old childViewController and this new childViewController using the below code.
func swapViewControllers(from : UIViewController, to : UIViewController) {
from.willMove(toParentViewController: nil)
self.addChildViewController(to)
to.view.frame = self.view.bounds
self.transition(from: from, to: to, duration: 1.0, options: UIViewAnimationOptions.transitionCrossDissolve, animations: nil) {
finished in
from.view.removeFromSuperview()
from.removeFromParentViewController()
to.didMove(toParentViewController: self)
}
}
Before calling this "swaptViewControllers()", I take the old childViewController by doing the following.
let oldChildViewController = self.childViewControllers.last
My problem is that this "oldChildViewController" is nil when I click one of those tabs for the first time right after the initial setup. So the function "swaptViewControllers()" does not even called because the self.childViewControllers is empty.
I have been struggling with this for few days now and could not find clear answer to solve this. So I decided to ask here to get some help about what might cause this.
Any help?? Thanks.
NOTE : I am using swift 3. Maybe this would help to answer my question since it seems lots of things changed fro swift 2.

PresentViewController presents compile error in static/class functions

I have a menu bar which I want to use on every page(UIViewController) in an app. So I figured I'd just write it once and use it on all the pages, instead of reproducing the same code on every page. To go about that, I created a new class which extends UIViewController(named it MenuBarViewController), with its own XIB file, created a function within that class which contains the code for generating the menubar, and just make a call to that function in any UIViewController where I want to place the menubar. Seems to work pretty seemlessly, but I run into problems when I tried to create some helper functions within the MenuBarViewController class, which trigger a navigation to another view, when one of the menu icons is tapped. I will include a simplified version of the code I'm working with below which illustrates the entirety of the problem.
class MenuBarViewController: UIViewController {
func menuBar(viewController:UIViewController){
let menuBar = UIView(frame:CGRectMake(0,0,100,20 ))
menuBar.backgroundColor = UIColor.blackColor()
viewController.view.addSubview(menuBar) //Add the newly created view to the main view(self)
//Add an icon view to the menubar
let iconView = UIImageView(frame: CGRectMake(5,0,5,5))
menuBar.addSubview(iconView)
//Add a gesture recognizer for the icon view
iconView.userInteractionEnabled = true
let tapHomeButton = UITapGestureRecognizer(target: self, action:#selector(MenuBarViewController.goToHomeView(_:)))
iconView.addGestureRecognizer(tapHomeButton)
//Add an icon to the icon view
let iconImageName = UIImage(named:"home.png")!
iconView.image = iconImageName
}
//Helper function to handle the gesture recognizer, helps transition to another view
func goToHomeView(sender: UIImageView!) {
appData.lastView = "GameViewController"
let settingsVC = SettingsViewController(nibName: "SettingsViewController", bundle: nil)
presentViewController(settingsVC, animated: true, completion: nil)
}
}
Now when I tap on the icon, there is no response. So I figured I'd declare the class functions(menuBar and goToHomeView) as either "class" or "static" funcs, and then call the menu bar directly with the class name. But then I get this compile error "extra argument 'animated' in call" on the this line:
presentViewController(settingsVC, animated: true, completion: nil)
So something must be wrong with the presentViewController method when it is declared within a static or class function because when I have the goToHomeView function just do something as simple as printing some text, it works fine. So I'm at a total loss at this point. What to do? Am I going about this the completely wrong way?

Presented TabBarController disappearing after attempted segue

Short synopsis (XCode 7.2, Swift2, iOS 9.2 as target):
1) In a first.storyboard, I have a single viewController.
2) In a second.storyboard, I have a tabbarController, with multiple navigationControllers with tableviewControllers (see attached image). Also of note is when second.storyboard is the one used on launch, everything works correctly.
3) the main UI for the app is in the first.storyboard, and I want to present the tabbarcontroller in the second.storyboard
4) No matter which way I present it (storyboard reference/segue, presentViewController, showViewController), the tabbarcontroller and all the initial views work, but if I tap a tableviewcell to segue to another view, the whole tabbarcontroller and contents disappear, leaving me back at the viewcontroller in first.storyboard.
I can cheat, and set the rootViewController manually and things seem to work
let sb = UIStoryboard(name: "second", bundle: nil)
let navController = sb.instantiateViewControllerWithIdentifier("secondIdentifier") as! UITabBarController
UIApplication.sharedApplication().keyWindow?.rootViewController = navController
And I suspect I can add an animation to this to not have the transition not be so stark. But this seems like something I shouldn't have to do, and kind of a pain to troubleshoot in the future. Am I missing something fundamental in making this work?
EDIT: Video of it not working https://youtu.be/MIhR4TVd7CY
NOTE: The last app I made originally targeted iOS4, and I did all the views programatically. It seemed like all the updates to IB and segues etc would make life more manageable (and for the most part that has been true), but this is still my first foray in to it, so I may be missing some important points of information to describe the issue.
I have found a superior way to deal with this: UIViewControllerTransitioningDelegate
It's a bit of extra work to implement, but it produces a "more correct" result.
My solution was to make a custom UIStoryboardSegue that will do the animation as well as set the rootViewController.
import UIKit
class changeRootVCSeguePushUp: UIStoryboardSegue {
override func perform() {
let applicationDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let sourceView = self.sourceViewController.view
let destinationView = self.destinationViewController.view
let sourceFrame = sourceView.frame
let destinationStartFrame = CGRect(x: 0, y: sourceFrame.height, width: sourceFrame.width, height: sourceFrame.height)
let destinationEndFrame = CGRect(x: 0, y: 0, width: sourceFrame.width, height: sourceFrame.height)
destinationView.frame = destinationStartFrame
applicationDelegate.window?.insertSubview(self.destinationViewController.view, aboveSubview: self.sourceViewController.view )
UIView.animateWithDuration(0.25, animations: {
destinationView.frame = destinationEndFrame
}, completion: {(finished: Bool) -> Void in
self.sourceViewController.view.removeFromSuperview()
applicationDelegate.window?.rootViewController = self.destinationViewController
})
}
}
I could not find a way in interface builder, or in code other than changing the rootViewController to get this working. I would end up with various random navigation issue like overlapping navigation bars, segue animations not working correctly until I changed tabs, full on lockups with no information in the console, etc.
I have previously presented a tabBarcontroller modally (without changing rootviewController), but everything was done in code (working as of ios7 and objective-c). No clue what is going on under the covers when the view hierarchies are made in a storyboard, but wondering if this is perhaps a bug.
Thanks to multiple other answers here on stackoverflow to get to mine!

Replacing the UIWindow's rootViewController while using a transition, appears to be leaking

Environment
iOS 9.2
Xcode 7.2
I'm looking to replace the UIWindow's rootViewController with an animation while also removing it from the view hierarchy as well.
class FooViewController: UIViewController
{
}
class LeakedViewController: UIViewController
{
}
Then initiate the transition in the AppDelegate simply by
self.window!.rootViewController = LeakedViewController()
let fooViewController = FooViewController()
self.window!.rootViewController?.presentViewController(fooViewController, animated: true){ unowned let window = self.window!
window.rootViewController = fooViewController
}
Profiling this in Instruments, notice that the rootViewController is still in memory.
Also came across this bug report which seems to suggest the same issue is present in iOS 8.3 and still Open.
Haven't been able to find any references to suggest that as part of the
UIViewController.presentViewController(animated:completion:)
the source view controller is retained (most likely by the UIPresentationController?) or if this is a bug. Notice that the UIPresentationController was first introduced in iOS 8.
If that's by design, is there an option to release the source view controller?
Using a subclass of UIPresentationController with
override func shouldPresentInFullscreen() -> Bool {
return true
}
override func shouldRemovePresentersView() -> Bool {
return true
}
doesn't seem make any difference. Haven't been able to locate anything else in the SDK.
Currently the only way I have found is to use a UIViewController, with a snapshot of what's currently on screen, in place of the root view controller before making the transition.
let fooViewController = FooViewController()
let view = self.window!.snapshotViewAfterScreenUpdates(false)
let viewController = UIViewController()
viewController.view.addSubview(view)
self.window!.rootViewController = viewController
self.window!.rootViewController?.presentViewController(dashboardViewController!, animated: true){ unowned let window = self.window!
window.rootViewController = fooViewController
}
It does work, tho in the console the following warning appears
Unbalanced calls to begin/end appearance transitions for <UIViewController: 0x79d991f0>.
Any ideas on the original question or the warning message appreciated.
Update
I believe I have narrowed it down to this one retain that's missing a release.
That is the possible offending call.
0 UIKit -[UIPresentationController _presentWithAnimationController:interactionController:target:didEndSelector:]
I logged that bug report; I have had no response from Apple engineering on it.
The sample code I submitted with the bug report demonstrating the issue is at https://github.com/adurdin/radr21404408
As far as I am aware, the issue is still present in current versions of iOS, but I have not tested exhaustively. Who knows, perhaps 9.3 beta fixes it? :)
In the application where I encountered this bug, we had been using custom transitions and rootViewController replacement for the majority of screen transitions. I have not found a solution to this leak, and because of reasons could not easily remove all the rootViewController manipulation, so instead worked around the issue by minimising where we used presentViewController and friends, and carefully managing the places where we required it.
One approach that I think has potential to avoid the bug while still retaining similar capabilities to rootViewController swapping--but have not yet implemented--is to have the rootViewController be a custom container view controller that occupies the full screen, and defines a presentation context. Instead of swapping the window's rootViewController, I would swap the single child view controller in this container. And because the container defines the presentation context, the presentations will occur from the container instead of the child being swapped. This should then avoid the leaks.
Inspired by #Jordan Smiths comment my fix ended with a one liner (thanks to the beauty of Swift):
window.rootViewController?.dismissViewControllerAnimated(false, completion: nil)
My complete code to swap the rootViewController with an animation then looks like:
func swapRootViewController(newController: UIViewController) {
if let window = self.window {
window.rootViewController?.dismissViewControllerAnimated(false, completion: nil)
UIView.transitionWithView(window, duration: 0.3, options: .TransitionCrossDissolve, animations: {
window.rootViewController = newController
}, completion: nil)
}
}
With that my memory leak disappeared :-)
The problem is probably that the presented controller and the presenting view controller refer to each other.
I could only get this to work by instantiating two copies of the transitioned-to view controller. One for presenting on the current root and one for replacing the current root after presentation. The copies are easy to achieve for me, since the presented VC's are simple objects. The presented view is left in the window hierarchy after dismissal, so that has to be removed manually after swapping in the new VC.
Here's some Swift.
private func present(_ presented: UIViewController, whenPresentedReplaceBy replaced: #escaping () -> UIViewController)
{
presented.modalTransitionStyle = .crossDissolve
let currentRoot = self.window?.rootViewController
currentRoot?.present(presented, animated: true)
{
let nextRoot = replaced()
self.window?.rootViewController = nextRoot
currentRoot?.dismiss(animated: false) {
currentRoot?.view?.removeFromSuperview()
}
}
}

Set initial viewController in Navigation controller programmatically (Layer SDK)

I want to add Layer SDK to my application (using Swift).
All view controllers here are created programmatically. Therefore I can't segue to them. I have 4 tabs in my application (UITabBarController). One of them is chat. In the chat tab I created a segue to UINavigationController. Now I want to load conversationListViewController in this UINavigationController. For that I created a class for this UINavigationController i.e. ConversationListViewController and added the following code:
class ChatNavigationViewController: UINavigationController {
var conversationListViewController: ConversationListViewController!
var layerClient: LYRClient!
override func viewDidLoad() {
let appDelegate = UIApplication.sharedApplication().delegate as!AppDelegate
self.layerClient = appDelegate.layerClient
self.conversationListViewController = ConversationListViewController(layerClient: appDelegate.layerClient)
self.conversationListViewController.displaysAvatarItem = true
self.navigationController!.pushViewController(self.conversationListViewController, animated: true)
}
}
But this is not working. And giving this kind of effect: the ConversationViewController is not loaded in UINavigationController. I am not sure if I am doing it the correct way. I'm searching for the correct way, but unable to find.
I Solved it. I dragged new NavigationViewController and added ConversationListViewController to rootviewController.I think i should try this first. Anyways thanks guys for your help.
Because you want to do this programatically:
You need to manually initialize the controller before stacking it up on the Navigation Controller. Try this:
navigationController?.pushViewController(self.conversationListViewController.init(), animated: true)

Resources