UITableView crashes if loaded from ContainerView - xcode

I've a big big problem related with a tableview (with a prototype cell made in IB) being loaded in a Container View. It loads perfectly, but when I try to tap or scroll over it just crashes with
respondsToSelector:]: message sent to deallocated instance 0x79a96e20
If I load the ViewController where the tableview is (without being embedded in a container view) it just works, which makes me think that has something to do with tableview being unallocated after parent viewcontroller finishes its loading process.
I'm pretty new with this and it's making me mad!!
Thanks for your help.
(THE VIEWCONTROLLER WHICH FILLS THE CONTAINERVIEW)
class cgGameViewerController: UIViewController {
#IBOutlet var cgGame:UIView; //Connected to IB ContainerView
override func viewDidLoad() {
var cgGameController=self.storyboard.instantiateViewControllerWithIdentifier("myIBviewController") as cgGameViewController;
self.cgGame.addSubview(cgGameController.view);
super.viewDidLoad()
}
}
(THE VIEWCONTROLLER WHICH IS LOADED IN A CONTAINERVIEW. In IB, UITableView delegate and datasource, is attached to the viewcontroller)
class cgGameViewController: UIViewController,UICollectionViewDataSource,UICollectionViewDelegate,UITableViewDelegate,UITableViewDataSource {
func tableView(tableView:UITableView!, numberOfRowsInSection section:Int) -> Int {
return 5;
}
func tableView(tableView:UITableView!, cellForRowAtIndexPath indexPath:NSIndexPath!) -> UITableViewCell! {
var myCell:UITableViewCell=tableView.dequeueReusableCellWithIdentifier("myCellInIB", forIndexPath: indexPath) as UITableViewCell;
return myCell;
}
}

Related

sending image from popover to parent view

I have a view that opens another view Controller as popover
the popover uses an image picker and displays the chosen image in an imageView.
The parent also has an imageView with an IBoutlet named profiler and before dismissing the popover i would like the parent view to get the chosen image.
How would i go about accessing parent and sending the image from the popover to the parent view
below is code from the popover view controller:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
picker.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//MARK: - Delegates
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject])
{
let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage //2
myImageView.contentMode = .scaleAspectFit //3
myImageView.image = chosenImage //4
myImageView.layer.borderWidth = 1
myImageView.layer.masksToBounds = false
myImageView.layer.borderColor = UIColor.black.cgColor
myImageView.layer.cornerRadius = myImageView.frame.height/4
myImageView.clipsToBounds = true
dismiss(animated:true, completion: nil) //5
}
thanks for any help rendered
Use a callback closure, it's less effort than delegate/protocol
In the popover view controller add a property
weak var callback : ((UIImage) -> ())?
Call it in didFinishPickingMediaWithInfo before dismiss
callback?(chosenImage)
In the parent view controller after creating the controller add
popoverViewController.callback = { image in
// do something with the image
}
popoverViewController is the popover view controller instance
you should create protocol
protocol PopOverImagePickerDelegate: NSObjectProtocol {
func didSelect(image: UIImage)
}
inside your PopoverViewController create
weak var delegate: PopOverImagePickerDelegate?
before navigating to PopoverViewController from ParentViewController set
popOverViewController.delegate = self
and then create
extension ParentViewController: PopOverImagePickerDelegate {
func didSelect(image: UIImage) {
//do stuff
}
}
and when image picked inside PopoverViewController just call
self.delegate?.didSelect(image: image)

Replace NSViewController under Swift2 Storyboard MAC OSX

I am new to Mac OSX and with Apple promoting the fact that the bodies of code are becoming similar decided to tell the folk I am writing code for we should be able to do a Mac OSX version. iPhone and iPad versions are all good and about to release second version so no issues there.
So I am subclassing NSWindowController to get access to the Toolbar and worked out how to remove and add items on the toolbar, but for the life of me I can not get one NSViewController (firstViewController) to dismiss and bring up the second NSViewController (secondViewController) in the same NSWindowController.
So the 2 issues are that
1. I want to be able to performSegueWithIdentifier from the first NSViewController in code and
2. bring up the second NSViewController by replacing the first NSViewController in the same NSWindowController.
If I add a button to the firstViewController and put a segue to the secondViewController then when I select the button the secondViewController comes up just fine but in a seperate window not the same NSWindowController that I want it to and the firstViewController does not get replaced but stays in the NSWindowController.
So I know the segue idea will work but its not working in code and when I do insert the segue from a button it works but into a seperate NSViewController that is not part of the NSWindowController.
I am trying to find some programming guide from Apple on the issue but no luck so far.
Here is an overview from my Storyboard:
Here is my NSWindowController subclassed and the func loginToMe2Team is trigger from the NSToolBar and its working just find as the print statements show up on the console.
import Cocoa
class me2teamWindowsController: NSWindowController {
#IBOutlet var mySignUp : NSToolbarItem!
#IBOutlet var myToolbar : NSToolbar!
let controller = ViewController()
override func windowDidLoad() {
super.windowDidLoad()
print("window loaded")
}
override func windowWillLoad() {
print("window will load")
}
#IBAction func logInToMe2Team(sender: AnyObject){
controller.LogIn() //THIS IS THE FUNC I AM TESTING WITH
}
#IBAction func signUpToMe2Team(sender: AnyObject){
controller.signUp()
}
Here is my NSViewController subclassed with the func LogIn. Its getting selected just fine but the performSegueWithIdentifier is not. And I did cut and past the Identifier to make absolutely sure it was the same.
import Cocoa
import WebKit
class ViewController: NSViewController {
#IBOutlet weak var theWebPage: WebView!
#IBOutlet weak var progressIndicator: NSProgressIndicator!
override func viewDidLoad() {
super.viewDidLoad()
let urlString = "https://thewebpage.com.au"
self.theWebPage.mainFrame.loadRequest(NSURLRequest(URL: NSURL(string: urlString)!))
}
override func viewDidAppear() {
}
func LogIn() {
print("I logged in")
self.performSegueWithIdentifier("goToTeamPage", sender: self)
//THIS IS THE BIT THATS NOT WORKING
}
func signUp() {
print("I have to sign up now")
}
override var representedObject: AnyObject? {
didSet {
}
}
func webView(sender: WebView!, didStartProvisionalLoadForFrame frame: WebFrame!)
{
self.progressIndicator.startAnimation(self)
}
func webView(sender: WebView!, didFinishLoadForFrame frame: WebFrame!)
{
self.progressIndicator.stopAnimation(self)
}
}
You need to use a custom segue class (or possibly NSTabViewController if it’s enough for your needs). Set the segue’s type to Custom, with your class name specified:
…and implement it. With no animation, it’s simple:
class ReplaceSegue: NSStoryboardSegue {
override func perform() {
if let src = self.sourceController as? NSViewController,
let dest = self.destinationController as? NSViewController,
let window = src.view.window {
// this updates the content and adjusts window size
window.contentViewController = dest
}
}
}
In my case, I was using a sheet and wanted to transition to a different sheet with a different size, so I needed to do more:
class ReplaceSheetSegue: NSStoryboardSegue {
override func perform() {
if let src = self.sourceController as? NSViewController,
let dest = self.destinationController as? NSViewController,
let window = src.view.window {
// calculate new frame:
var rect = window.frameRectForContentRect(dest.view.frame)
rect.origin.x += (src.view.frame.width - dest.view.frame.width) / 2
rect.origin.y += src.view.frame.height - dest.view.frame.height
// don’t shrink visible content, prevent minsize from intervening:
window.contentViewController = nil
// animate resizing (TODO: crossover blending):
window.setFrame(window.convertRectToScreen(rect), display: true, animate: true)
// set new controller
window.contentViewController = dest
}
}
}

Save UITableView names to array on button action

I want to save the names that are filled in UITableView to an array
var mineSpillere = [String]()
How can I do this on buttonAction?
This is button action for how i add names to tableview:
#IBAction func addButtonAction(sender: AnyObject) {
mineSpillere.append(namesTextBox.text)
myTableView.reloadData()
}
and also here code:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell = self.myTableView.dequeueReusableCellWithIdentifier("cell") as! UITableViewCell
cell.textLabel!.text = self.mineSpillere[indexPath.row]
return cell;
}
That only when I press the "back" button in the application, the names from the UITableView will be saved in an array.
I am going to access these names from another view controller also, so i need them to be saved as an array.
Okay so it looks like you have all the data in the mineSpillere array already as you're using cell.textLabel!.text = self.mineSpillere[indexPath.row] so to get that array back to the first view controller. You could use the following code in the view controller that is being presented when the 'back' button is being pressed:
class FirstViewController: UIViewController,SecondViewControllerDelegate {
var mineSpillereCopyFromSecondVC = [String]()
func presentSecondViewController() {
// Im not sure the class name for you're second view
// where the tableView is located.
var secondVC: SecondViewController = SecondViewController();
secondVC.delegate = self
// Also not too sure on how you're presenting the `SecondViewController` so I'm goingg to leave that empty.
// The important part is just above us.
}
func passMineSpillere(mineSpillere: [String]) {
// This class now has the mineSpiller array of name.
self.mineSpillereCopyFromSecondVC = mineSpillere
}
}
And then in you SecondViewController where the tableView is located you could add the following code.
import UIKit
protocol SecondViewControllerDelegate {
func passMineSpillere(mineSpillere:[String])
}
class SecondViewController: UIViewController {
var delegate: SecondViewControllerDelegate?
var mineSpillere = [String]()
// This will be called when the 'back' button is pressed.
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
// Pass the mineSpillere array back to the delegate
// which is the firstViewController instance.
self.delegate?.passMineSpillere(self.mineSpillere)
}
}

How can I animate any UIView inside UITableViewCell?

let label = UILabel(frame: CGRectMake(20.0, 20.0, 15.0, 15.0))
label.backgroundColor = UIColor.flamingoColor()
UIView.animateWithDuration(3.0, animations: {
cell.addSubview(label)
label.backgroundColor = UIColor.yellowColor()
})
This code I put inside tableView:cellForRowAtIndexPath: -> result is a subview that has a yellow background, but I haven't seen any animation. The same is for method tableView:didEndDisplayingCell:
Which method should I use or what kind of animation should I put there to see any animations inside UITableViewCell. I know that I cannot animate existing labels, because these are with constraints.
Firstly, you should move cell.addSubview(label) to outside of the animation block and add the label to the contentView of the cell.
Back to your problem. You can't animate the background colour of a UILabel. You could use a UIView, of the same size, behind the UILabel for the same effect though.
To get the UIView to change colour once it's appeared I used a UITableViewCell subclass:
class AnimatedCell : UITableViewCell {
let animatedView = UIView()
/* Setup by adding animatedView to the contentView and setting the
animated view's initial frame and colour.
*/
func animate() {
UIView.animateWithDuration(3.0) {
animatedView.backgroundColor = UIColor.redColor()
}
}
Then in your UITableViewController subclass, when the view controller is presented the UITableView will be populated so you need to animate those cells with:
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated: Bool)
for cell in tableView.visibleCells() as! [UITableViewCell] {
if let animatedCell = cell as? AnimatedCell {
animatedCell.animate()
}
}
}
Then, for cells that appear when you scroll:
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
if let animatedCell = cell as? AnimatedCell {
a.animateLabel()
}
}
Also, you can animate with AutoLayout, you need to change the constant on the NSLayoutConstraint you want to animate. This gives a good example: iOS: How does one animate to new autolayout constraint (height)

Display a view for few seconds (custom push from NavController)

I started with Master-Detail Application. Now I try to add a custom View (default UIViewController with simple Label) which will be displayed for some seconds (like a loading view) before detail/master views will be accessible.
My Problem now is that if I add my ViewController to AppDelegate and push to it from NavigationController i get an empty view.
See here:
I didn't change anything but adding just one line of code to appdelegate:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
let splitViewController = self.window!.rootViewController as UISplitViewController
let navigationController = splitViewController.viewControllers[splitViewController.viewControllers.count-1] as UINavigationController
navigationController.topViewController.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem()
splitViewController.delegate = self
let masterNavigationController = splitViewController.viewControllers[0] as UINavigationController
let controller = masterNavigationController.topViewController as MasterViewController
controller.managedObjectContext = self.managedObjectContext
// +++ Custom ViewController is to be displayed from here +++
navigationController.pushViewController(ViewController(), animated: true)
return true
}
I do not get where the problem is...
With this line in your code
navigationController.pushViewController(ViewController(), animated: true)
you are instantiating a new, empty view controller, whis is probably not what you want.
Get a reference to your storyboard (i.e from your masterviewcontroller) to create the view controller and push this one on the navigation stack. Example:
if let myVC = controller.storyboard!.instantiateViewControllerWithIdentifier(...) {
navigationController.pushViewController(myVC, animated: true)
}

Resources