I tried to implement iCarousel as per this tutorial: https://medium.com/#arb1nsnmgl/icarousel-walkthrough-swift-3-0-887554155242
but when trying to implement the #protocol it gives me 4 error messages:
Expected '{' in protocol type
Expected an attribute name
Protocol 'iCarouselDataSource' cannot be nested inside another declaration
Protocols do not allow generic parameters; use associated types instead
Currently the code looks like this:
import UIKit
class ViewController: UIViewController {
#IBOutlet var carouselView: iCarousel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//Testing
#protocol iCarouselDataSource <NSObject>
-(NSInteger)numberOfItemsInCarousel:(iCarousel *)carousel;
-(UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSInteger)index reusingView:(nullable UIView *)view;
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
You are adding it at wrong place so remove
#protocol iCarouselDataSource <NSObject>
-(NSInteger)numberOfItemsInCarousel:(iCarousel *)carousel;
-(UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSInteger)index reusingView:(nullable UIView *)view;
From viewDidLoad method.
Above methods are delegate methods. And you need to add it as shown in tutorial.
Check point 11 for that.
Also confirm the delegates as shown in point number 8.
Related
Im trying to make a simple app but am unable to make an IBOutlet like I was able to before, now you don't have the option in swift to change the connection to an Outlet instead of an action. I believe this could be because of the update in the Software as it is now Swift version 9.1. Thank you in advance!
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
You have dragged to the exit on the view controller. Drag directly (ctrl) from the storyboard to the code.
I have multiple ViewControllers in my storyboard, and I need various objects in the story board to link to vars in my code.
Screenshot of my ViewControllers
I'm only able to ctrl + drag an IBOutlet from the ViewController I initially began with, and changing the story entrance point doesn't affect the problem.
Code I am trying to link
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#objc func didTapButton(_ tap: UITapGestureRecognizer) {
}
}
extension ViewController: UIViewControllerTransitioningDelegate {
}
Make sure you specified the correct "Custom Class" for each of your view controllers.
That is, set ViewController as the custom class for each of your view controllers.
Like this:
Link the UIView class you want to connect with the UIView in the storyboard.
Consider the following code. Everything is done by the book, except that the delegate is assigned an instance of some other class other than self. Yet this code fails - the delegate is never called. Why is that?
class My: UITextField {
...
init(...) {
delegate = MyDelegate()
}
}
public class MyDelegate: NSObject, UITextFieldDelegate {
public func textFieldDidBeginEditing(_ textField: UITextField) {
print("MyDelegate was called")
}
}
If your delegate property is defined using a weak var, the MyDelegate instance won't be retained. Without a strong reference it will shortly be deallocated and no longer exist to receive calls.
Your example code strays from the typical delegate pattern:
Delegation and the Cocoa Frameworks
The delegating object is typically a framework object, and the
delegate is typically a custom controller object.
The text field's view controller would commonly assign itself as the text field's delegate:
class MyViewController: UITextFieldDelegate {
...
func viewDidLoad() {
myTextField.delegate = self
}
func textFieldDidBeginEditing(_ textField: UITextField) {
print("textFieldDidBeginEditing")
}
}
didLoad is not a function of UITextField so your delegate is not really set and that is why it is not called. If you are creating your My class programmatically, you can set the delegate after the instance is created.
let myTextField = My()
mytextField.delegate = MyDelegate()
If you want to set the delegate everytime you class is created, you need to override the init functions of UITextField and create the delegate inside your init functions.
class MyTF : UITextField
{
override init(frame: CGRect)
{
super.init(frame: frame)
delegate = MyDelegate()
}
required init?(coder aDecoder: NSCoder)
{
super.init(coder: aDecoder)
delegate = MyDelegate()
}
}
You can achieve this by creating a strong reference to your delegate class first with "let", and then setting the delegate. Otherwise, because the delegate reference is weak it will have a zero reference count and nil out, leaving you with no delegate.
let theDelegate = MyDelegate()
delegate = theDelegate
I started working on this question app.
I began by tableView of the categories:
For data exchange, I decided to use a protocol:
protocol Category {
func data(object:AnyObject)
}
In the first ViewController has the following code:
class ViewController: UIViewController {
var items:[String] = ["Desktop","Tablet","Phone"]
let CategoriesData:Category? = nil
override func viewDidLoad() {
super.viewDidLoad()
CategoriesData?.data(items)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
In the second ViewController (tableView in Container) have the following code:
class CategoriesViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, Category {
#IBOutlet var table: UITableView!
var items:[String] = []
func data(object: AnyObject) {
self.items = (object as? [String])!
print(object)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.items.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:TableViewCell = self.table.dequeueReusableCellWithIdentifier("SegueStage") as! TableViewCell
cell.nameLabel.text = items[indexPath.row]
return cell
}
}
For me, apparently it's all right. But nothing appeared on the simulator.
My question is: If the Container use to present another viewController as passing data by protocols should be done?
EDITED
I answered why the TO:s solution didn't work as intended, but I just realised that I haven't given a viable answer to how to use protocols as delegates for the ViewController -> ViewController communication. I'll leave the half-answer below until someone can possibly answer the full question better.
In the way protocol is used in your code, you define your protocol Category to be a delegate for instances of the type ViewController. When an instance of type ViewController is initialised in---and hence owned locally in the scope of---some other class, the instance can delegate callbacks to the owning class.
The problem is that your CategoriesViewController does not contain any instances of type ViewController. We note that both these classes are, in themselves, subclasses of UIViewController, but none of them contain instances of one another. Hence, your CategoriesViewController does indeed conform to protocol Category, by implemented the protocol method data(...), but there's no ViewController instance in CategoriesViewController that can do callbacks to this function. Hence, your code compile file, but as it is, method data(...) in CategoriesViewController will never be called.
I might be mistaken, but as far as I know, protocol delegates are used to do callbacks between models (for model in MVC design) and controllers (see example below), whereas in your case, you want a delegate directly between two controllers.
As an example of model-delegate-controller design, consider some custom user control, with some key property value (e.g. position in rating control), implemented as a subclass of UIView:
// CustomUserControl.swift
protocol CustomUserControlDelegate {
func didChangeValue(value: Int)
}
class CustomUserControl: UIView {
// Properties
// ...
private var value = 0 {
didSet {
// Possibly do something ...
// Call delegate.
delegate?.didChangeValue(value)
}
}
var delegate: CustomUserControlDelegate?
// ... some methods/actions associated with your user control.
}
Now lets assume an instance of your CustomUserControl is used in a a view controller, say ViewController. Your delegate functions for the custom control can be used in the view controller to observe key changes in the model for CustomUserControl, much like you'd use the inherent delegate functions of the UITextFieldDelegate for UITextField instances (e.g. textFieldDidEndEditing(...)).
For this simple example, use a delegate callback from the didSet of the class property value to tell a view controller that one of it's outlets have had associated model update:
// ViewController.swift
Import UIKit
// ...
class ViewController: UIViewController, CustomUserControlDelegate {
// Properties
// ...
#IBOutlet weak var customUserControl: CustomUserControl!
// Instance of CustomUserControl in this UIViewController
override func viewDidLoad() {
super.viewDidLoad()
// ...
// Custom user control, handle through delegate callbacks.
customUserControl.delegate = self
}
// ...
// CustomUserControlDelegate
func didChangeValue(value: Int) {
// do some stuff with 'value' ...
}
}
Is there a way to detect when a UITextView has finished scrolling? As a note, I allow the user to enable or disable paging.
Thanks.
UITextView is a subclass of UIScrollView, which has a UIScrollViewDelegate class for controlling behaviour related to scrolling. One of its methods is scrollViewDidEndDecelerating. You can make your view controller implement this protocol, set your UITextView's delegate property to the view controller, and then implement the scrollViewDidEndDecelerating method. When the method is called, the UITextView will have finished scrolling. e.g.:
in .h:
#interface MyViewController : UIViewController <UIScrollViewDelegate>
in .m:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
NSLog(#"Finished scrolling");
}
In Swift:
class MyViewController: UIViewController, UITextViewDelegate {
weak var textView: UITextView!
override func viewDidLoad() {
self.textView.delegate = self
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
...
}
}
UITextViewDelegate inherits UIScrollViewDelegate