I am working with the IF/Else training in Udemy and cannot see where my error/issue is.
When I run the code, nothing happens and it doesn't activate an error(in XCode)
When I apply it to the (online)playground, it's identifying almost everything as an error.
I'm a beginner. I'm follwong the lessons but if she doesn't supply the solution, I can't see where I went wrong. Help.
import UIKit
class ViewController: UIViewController {
let softTime = 5
let mediumTime = 7
let hardTime = 12
#IBAction func hardnessSelected(_ sender: UIButton) {
let hardness = sender.currentTitle
}
func hardness(temp: Int){
let hardness = Int.random(in: 0 ... 12)
if hardness >= 10 {
print("Hard Boiled")
};if hardness <= 9 {
print("Medium Boiled")
} else {
print("Soft Boiled")
}
}
}
You have an unnecessary semi-colon (';') on your second if, also you should use else if when you have another condition you want to check for. Try this code:
import UIKit
class ViewController: UIViewController {
let softTime = 5
let mediumTime = 7
let hardTime = 12
#IBAction func hardnessSelected(_ sender: UIButton) {
let hardness = sender.currentTitle
}
func hardness(temp: Int){
let hardness = Int.random(in: 0 ... 12)
if hardness >= 10 {
print("Hard Boiled")
} else if hardness <= 9 {
print("Medium Boiled")
} else {
print("Soft Boiled")
}
}
}
You can read more about javascript if statements here: https://www.w3schools.com/js/js_if_else.asp
Related
I can't seem to make this tableView with custom cells work. I get a runtime error
Terminating app due to uncaught exception 'NSUnknownKeyException',
reason: '[ setValue:forUndefinedKey:]: this class is not key
value coding-compliant for the key causeCampaignDescription.'
The weird thing is that that property is not called like that anymore. This is the cell file MainViewControllerTableViewCell
//
// MainViewControllerTableViewCell.swift
//
//
// Created by on 9/13/17.
// Copyright © 201. All rights reserved.
//
import UIKit
class MainViewControllerTableViewCell: UITableViewCell {
#IBOutlet weak var causeCampaignImageView: UIImageView!
#IBOutlet weak var causeDescription: UILabel!
#IBOutlet weak var daysToFinishLabel: UILabel!
#IBOutlet weak var raisedOverTotalLabel: UILabel!
#IBOutlet weak var percentageCompletedLabel: UILabel!
#IBOutlet weak var goalProgresView: UIProgressView!
//card used on
#IBInspectable var cornerradius : CGFloat = 2
#IBInspectable var shadowOffSetWidth : CGFloat = 0
#IBInspectable var shadowOffSetHeight : CGFloat = 5
#IBInspectable var shadowColor : UIColor = UIColor.black
#IBInspectable var shadowOpacity : CGFloat = 0.5
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
override func layoutSubviews() {
layer.cornerRadius = cornerradius
layer.shadowColor = shadowColor.cgColor
layer.shadowOffset = CGSize(width: shadowOffSetWidth, height: shadowOffSetHeight)
let shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: cornerradius)
layer.shadowPath = shadowPath.cgPath
layer.shadowOpacity = Float(shadowOpacity)
}
}
and this is the view controller that holds the table view MainViewController:
//
// ViewController.swift
//
//
// Created by on 1/28/17.
// Copyright © 2017. All rights reserved.
//
import UIKit
import Alamofire
import SwiftyJSON
import Firebase
class MainViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
var campaignRowsData = [CauseCampaign]()
var serverFetchCampaignsUrl = Config.Global._serverUrl
#IBOutlet weak var campaignTableView: UITableView!
//show navigation controller bar
var facebookID = "", twitterID = "",firebaseID = ""
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//hide bar from navigation controller
setToolbar()
campaignTableView.delegate=self
campaignTableView.dataSource=self
campaignTableView.separatorColor = UIColor(white: 0.95, alpha: 1)
recoverUserDefaults()
getCampaignList()
//print(facebookID, twitterID, firebaseID)
}
func setToolbar(){
//hide bar from navigation controller
self.navigationController?.isNavigationBarHidden = false
self.navigationItem.setHidesBackButton(true, animated: false)
self.navigationController?.navigationBar.barTintColor = UIColor.purple
}
func getCampaignList(){
Alamofire.request(serverFetchCampaignsUrl+"/campaigns/get/all/user/\(twitterID)/firebase/\(firebaseID)/cat/0", method: .get).validate().responseJSON { response in
switch response.result {
case .success(let data):
let campaignCausesJSON = JSON(campaignCausesData: data)
self.parseCampaignCausesListResponse(campaignCausesJSON)
//alternative thread operation
DispatchQueue.main.async {
self.campaignTableView.reloadData()
}
case .failure(let error):
print(error)
}
}
}
func parseCampaignCausesListResponse(_ campaignCausesJSON:JSON){
if let activeCampaignCount = campaignCausesJSON["active_campaigns_count"].string {
//Now you got your value
print("TOTAL_ACTIVE_CAMPAIGNS",activeCampaignCount)
CampaignsGlobalDataManagerUtil.campaignTotalCount = Int(activeCampaignCount)!
}
if let contributorUserId = campaignCausesJSON["contributor_user_id"].string {
//Now you got your value
print("CONTRIBUTOR_USER_ID",contributorUserId)
CurrentUserUtil.contributorUserId = contributorUserId
}
if let userTwitterFollowersQty = campaignCausesJSON["user_twitter_followers_qty"].int {
//Now you got your value
print("USER_TWITTER_FOLLOWERS_QTY",userTwitterFollowersQty)
CurrentUserUtil.twitterFollowersCount = Int(userTwitterFollowersQty)
}
//Parsing campaigns object array
campaignCausesJSON["camp_array"].arrayValue.map({
let campaignCause:JSON = $0
parseCampaign(campaignCause)
})
}
//TODO:CHANGE TO DATATAPE OBJECT
func parseCampaign(_ causeCampaign:JSON){
let causeCampaignObject: CauseCampaign = CauseCampaign();
causeCampaignObject.description = causeCampaign["cause_description"].stringValue
causeCampaignObject.id = causeCampaign["campaign_id"].stringValue
if let contributorsQty = causeCampaign["contributors_qty"].int{
causeCampaignObject.contributorsQty = contributorsQty
}
causeCampaignObject.currencySymbol = causeCampaign["currency_symbol"].stringValue
if let currentContributions = causeCampaign["current_contributions"].float{
causeCampaignObject.currentContributions = currentContributions
}
if let goal = causeCampaign["goal"].float {
causeCampaignObject.goal = goal
}
if let goalPercentageAchieved = causeCampaign["goal_percentage_achieved"].float{
causeCampaignObject.goalPercentageAchieved = causeCampaign["goal_percentage_achieved"].float!
}
causeCampaignObject.hashtag = causeCampaign["hashtag"].stringValue
causeCampaignObject.name = causeCampaign["name"].stringValue
if let remainingAmmountToGoal = causeCampaign["remaining_ammount_to_goal"].float{
causeCampaignObject.remainingAmmountToGoal = remainingAmmountToGoal
}
if let picUrl = causeCampaign["pic_url"].stringValue as? String {
causeCampaignObject.picUrl = picUrl
}
if let campaignStartingDate = causeCampaign["created_at"].string{
causeCampaignObject.campaignStartingDate = campaignStartingDate
}
if let campaignEndingDate = causeCampaign["campaign_ending_date"].string{
causeCampaignObject.campaignEndingDate = campaignEndingDate
}
var foundationsArray = [Foundation]()
causeCampaign["foundations"].arrayValue.map({
let id = $0["foundation_id"].stringValue
let twitterUsername = $0["twitter_username"].stringValue
let picPath = $0["pic_path"].stringValue
let name = $0["name"].stringValue
let foundation:Foundation = Foundation(id,twitterAccount: twitterUsername,picPath: picPath,name: name)
foundationsArray.append(foundation)
})
causeCampaignObject.foundations = foundationsArray
campaignRowsData.append(causeCampaignObject)
// foundations = "<null>";
//innecesario
// SACAR DE LA REQUEST INICIAL???
// "went_inactive_date" = "<null>";
// "tweet_id" = 900936910494810112;
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return campaignRowsData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = campaignTableView.dequeueReusableCell(withIdentifier: "campaignCell", for: indexPath) as! MainViewControllerTableViewCell
//setting card attributes
print("ROW",campaignRowsData[indexPath.row].description)
let campaignCause:CauseCampaign = campaignRowsData[indexPath.row]
if let desc = campaignCause.description as? String{
cell.causeDescription.text = desc
} else {
print("NULL")
}
return cell
}
func recoverUserDefaults(){
if let fbID = UserDefaults.standard.object(forKey: Config.Global._facebookIdUserDefaults) as? String {
facebookID = fbID
}else{
print("FACEBOOK ID IS NULL")
}
if let twtID = UserDefaults.standard.object(forKey: Config.Global._twitterIdUserDefaults) as? String{
twitterID = twtID
}else{
print("TWITTER ID IS NULL")
}
if let firID = UserDefaults.standard.object(forKey: Config.Global._firebaseIdUserDefaults) as? String{
firebaseID = firID
}else{
print("TWITTER ID IS NULL")
}
return
}
}
The app crashes if the line reloadData is uncommented (I don't even know when and If I should use this)
If I set a label you can't see anything on screen, I see blank cards, but again, as soon as I uncomment reloadData it crashes
There's no causeCampaignDescription, now it's called causeDescription so I don't know why the error keeps mentioning that field
The data desc is ok since I printed it and it has the right content so it's not that
What could be the problem?
Searching the project for causeCampaignDescription will often turn up the offending xib and/or storyboard containing the outdated key path. However, it's been my experience that Xcode is not always 100% reliable about finding things in xibs and storyboards, so if Xcode's search feature won't find it, this command in the Terminal will turn it up straightaway:
find /path/to/your/project/directory -name .git -prune -or -type f -exec grep causeCampaignDescription {} \; -print
Once you find the offending item in the xib or storyboard, change it to the correct string and you should solve your problem.
I am trying to implement waterfallLayout with a self sizing cell that should work with iOS >= 9.0
Something like pintrest collectionViewLayout not the transition but the difference is that i have a fixed ratio of image but fields below is dynamic which i used UIStackView.
The self sizing is working fine but my problem is in changing the cell origin to be always = 15 PX between cells.
so when i tried FlowLayout without any customisation everything is working fine except for the margins between cells is not correct but the scrolling is working well without any performance issue for iOS >= 9.0
After trying CustomizingFlowLayout the performance is so bad in iOS 10 things is not working while in iOS 9 works fine. i know that apple did some improvement with the UICollectionView but with me i don't see that improvement.
My Cell:
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
self.setNeedsLayout()
self.layoutIfNeeded()
layoutAttributes.bounds.size.height = systemLayoutSizeFitting(layoutAttributes.size, withHorizontalFittingPriority: UILayoutPriorityRequired, verticalFittingPriority: UILayoutPriorityFittingSizeLevel).height
return layoutAttributes
}
My controller:
ViewDidLoad {
layoutView = collectionView.collectionViewLayout as! CustomLayout
if #available(iOS 10.0, *) {
self.collectionView.isPrefetchingEnabled = false
}
layoutView.estimatedItemSize = CGSize(width: layoutView.cellWidth, height: 200)
}
extension RecipesCollectionWithSortBar: UICollectionViewDataSource {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return array.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: customCell.reuseIdentifier, for: indexPath) as! customCell
return cell
}
extension RecipesCollectionWithSortBar : UICollectionViewDelegateFlowLayout {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.bounds.maxY == scrollView.contentSize.height && !isLoadingMoreRecipes {
//
LoadMore
}
}
My CustomFlowLayout
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let attrs = super.layoutAttributesForElements(in: rect)
var attrsCopy = [UICollectionViewLayoutAttributes]()
for element in attrs! where (element.copy() as! UICollectionViewLayoutAttributes).representedElementCategory == .cell
&& element.frame.height != cacheCells[element.indexPath.item]?.frame.height {
if element.indexPath.item == 0 {
element.frame.origin.y = self.sectionInset.top
element.frame.origin.x = self.sectionInset.left
} else if element.indexPath.item == 1 {
element.frame.origin.y = self.sectionInset.top
element.frame.origin.x = cacheCells[0]!.frame.maxX + margin
} else {
let previous = cacheCells[element.indexPath.item - 2]
element.frame.origin.y = previous!.frame.maxY + self.minimumInteritemSpacing
element.frame.origin.x = previous!.frame.origin.x
}
cacheCells[element.indexPath.item] = element
attrsCopy.append(element)
}
let values = cacheCells.values.filter({ $0.frame.intersects(rect) })
return values.map({ $0 })
}
Here i have many problems :
1- i have a huge white space at the end of the collectionView because i changed the cell origin this problem only happens at iOS > 10.
i tried to override the content size
func getContentHeight() -> CGFloat {
if !cacheCells.values.isEmpty {
let attribute = cacheCells.values.max { $0.0.frame.maxY < $0.1.frame.maxY }
return attribute!.frame.maxY + sectionInset.bottom
}
return contHeight
}
override var collectionViewContentSize: CGSize {
return CGSize(width: self.cellWidth * CGFloat(columnCount), height: getContentHeight())
}
for some reason iOS 9 don't like this solution the scroll stops ..
2- Scrolling performance is so bad in iOS 10 and worst in iOS 9.0.
3- when i load more believe it or not it scroll 3 or 4 times and doesn't have more items to show when i print the log (i have 100 item but the collection view show only 70) and sometimes when hard scrolling it remembers that there's some more items and show them. i am not sure what i am doing wrong.
It's been 2 weeks now trying to figure out what's wrong may be having some fresh eye and mind can point on the problem i am having.
I have two buttons as right and left arrow on my main page and every time a button is clicked UILabel is updated through an array e.g let names = ["John, Smith, "Ahmed", "Jack", "Kathy"]. I have two UIActions as rightArrowClicked and leftArrowClicked. Initially the label should appear as John with left arrow disabled, which'll be done by the isHidden property of leftArrow and likewise when the value is Kathy then rightArrow should be disabled. Along with that i also need to update another label w.r.t to the name value e.g john can have a value of "cute", and kathy as "pretty" and these values are coming from an external library which i've added via cocoapods which are being generated in a function of that class. Any ideas how would i do that?
This is code with simple logic that you need
let names = ["John", "Smith", "Ahmed", "Jack", "Kathy"]
var currentIndex = 0
leftButton.isHidden = true
#IBAction func left(_ sender: Any) {
currentIndex --
label.text = names[currentIndex]
if currentIndex == 0 {
leftButton.isHidden = true
}
rightButton.isHidden = false
}
#IBAction func right(_ sender: Any) {
currentIndex ++
label.text = names[currentIndex]
if currentIndex == names.count - 1 {
rightButton.isHidden = true
}
leftButton.isHidden = false
}
You can try like below and call updateButtonsState() in viewDidLoad method
let names = ["John", "Smith", "Ahmed", "Jack", "Kathy"]
let nature = ["cute", "pretty", "cute", "pretty", "cute"]
var currenIndex = 0
#IBAction func leftBtnClick(_ sender: UIButton) {
currenIndex = currenIndex - 1
updateButtonsState()
}
#IBAction func rignthBtnClick(_ sender: UIButton) {
currenIndex = currenIndex + 1
updateButtonsState()
}
func updateButtonsState() {
leftBtn.isEnabled = currenIndex > 0 ? true : false
rightBtn.isEnabled = currenIndex < names.count - 1 ? true : false
if currenIndex >= 0 && currenIndex < names.count {
lblName.text = names[currenIndex]
lblNameWithNature.text = nature[currenIndex]
}
print("currenIndex == \(currenIndex)")
}
Hello i am trying to make a shop page on my application. The shop page contains a table with a title that is clickable so it expands into subcategories of that title. Etc click coffee and get some different kind of coffee to buy from.
Title = Drinks, Sandwiches & Drinks in the picture below.
subcategory from title = Ham & cheese, Chicken, bacon & curry .... and so on.
Now the expanding and closing the titles work fine. But when i press + (add iteem to cart) i get a out out of index if it's clicked in a specific order.
if i expand sandwiches (like it is in the picture) and then expand drinks (the one below sandwiches) and then click on the plus on any subcategory in sandwiches and then close sandwiches again and press on plus on any subcategory in Drinks (the one below the now closed sandwiches) the application will crash with a out of index error. Only this combination gives this error.
How the code works:
/* Create Cells */
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -
> UITableViewCell {
// Row is DefaultCell
if let rowData = destinationData?[indexPath.row] {
let defaultCell = Bundle.main.loadNibNamed("TableViewCellMenuItems", owner: self, options: nil)?.first as! TableViewCellMenuItems
// tableView.dequeueReusableCell(withIdentifier: "TableViewCellMenuItems", for: indexPath).first as! TableViewCellMenuItems
defaultCell.menuName.text = rowData.name
defaultCell.menuPicture.image = rowData.image
defaultCell.menuFoldPic.image = #imageLiteral(resourceName: "ic_keyboard_arrow_down")
defaultCell.selectionStyle = .none
return defaultCell
}
// Row is ExpansionCell
else {
if let rowData = destinationData?[getParentCellIndex(expansionIndex: indexPath.row)] {
// print("her åbner vi")
// // Create an ExpansionCell
let expansionCell =
Bundle.main.loadNibNamed("TableViewCellMenuItemExpanded", owner: self, options: nil)?.first as! TableViewCellMenuItemExpanded
// Get the index of the parent Cell (containing the data)
let parentCellIndex = getParentCellIndex(expansionIndex: indexPath.row)
// Get the index of the flight data (e.g. if there are multiple ExpansionCells
let flightIndex = indexPath.row - parentCellIndex - 1
// Set the cell's data
expansionCell.itemPrice.text = String (describing: "\(rowData.menuItems![flightIndex].price) kr")
expansionCell.itemName.text = rowData.menuItems?[flightIndex].name
expansionCell.itemCount.text = String (describing: rowData.menuItems![flightIndex].count)
// expansionCell.itemCount.text = String (describing: indexPath.row)
expansionCell.itemAdd.tag = Int(indexPath.row)
expansionCell.itemMinus.tag = Int(indexPath.row)
expansionCell.itemAdd.addTarget(self, action: #selector(HomeSelectedShopViewController.plus(_:)), for: .touchUpInside)
expansionCell.itemMinus.addTarget(self, action: #selector(HomeSelectedShopViewController.minus(_:)), for: .touchUpInside)
expansionCell.selectionStyle = .none
return expansionCell
}
}
return UITableViewCell()
}
as you can see the expansionCells get a tag for my function plus and minus (so i can know which indexPath i should add up or down)
Plus function:
func plus(_ sender: AnyObject?) {
if let rowData = destinationData?[getParentCellIndex(expansionIndex: sender!.tag)] {
self.table.reloadData()
// Get the index of the parent Cell (containing the data)
let parentCellIndex = getParentCellIndex(expansionIndex: sender!.tag)
// Get the index of the flight data (e.g. if there are multiple ExpansionCells
let flightIndex = sender!.tag - parentCellIndex - 1
print(sender!.tag)
print(flightIndex)
print(rowData.menuItems!.count)
var con = 0;
for a in rowData.menuItems! {
print("her er navn : \(a.name) og her er id \(con)")
con += 1
}
let data = rowData.menuItems![flightIndex]
let item = Items(name: data.name, price: data.price, count: data.count)
var counter = 0;
for x in self.basket {
if(x.name == item.name || x.price == item.price)
{
counter = counter+1;
}
}
if(counter >= 99)
{
}
else
{
DispatchQueue.main.async {
self.basket.append(item)
self.updateBasket()
rowData.menuItems![flightIndex].count = rowData.menuItems![flightIndex].count+1;
self.table.reloadData()
}
}
}
}
Rest of the functions:
/* Expand cell at given index */
private func expandCell(tableView: UITableView, index: Int) {
// print("when is this run 1")
// Expand Cell (add ExpansionCells
if let flights = destinationData?[index]?.menuItems {
for i in 1...flights.count {
destinationData?.insert(nil, at: index + i)
tableView.insertRows(at: [NSIndexPath(row: index + i, section: 0) as IndexPath] , with: .top)
}
}
}
/* Contract cell at given index */
private func contractCell(tableView: UITableView, index: Int) {
// print("when is this run 4")
if let flights = destinationData?[index]?.menuItems {
for i in 1...flights.count {
destinationData?.remove(at: index+1)
tableView.deleteRows(at: [NSIndexPath(row: index+1, section: 0) as IndexPath], with: .top)
}
}
}
/* Get parent cell index for selected ExpansionCell */
private func getParentCellIndex(expansionIndex: Int) -> Int {
// print("when is this run 5")
var selectedCell: Menu?
var selectedCellIndex = expansionIndex
while(selectedCell == nil && selectedCellIndex >= 0) {
selectedCellIndex -= 1
selectedCell = destinationData?[selectedCellIndex]
}
return selectedCellIndex
}
func minus(_ sender: AnyObject?) {
if let rowData = destinationData?[getParentCellIndex(expansionIndex: sender!.tag)] {
// Get the index of the parent Cell (containing the data)
let parentCellIndex = getParentCellIndex(expansionIndex: sender!.tag)
// Get the index of the flight data (e.g. if there are multiple ExpansionCells
let flightIndex = sender!.tag - parentCellIndex - 1
let data = rowData.menuItems![flightIndex]
let item = Items(name: data.name, price: data.price, count: data.count)
DispatchQueue.main.async {
var counter = 0;
for x in self.basket {
if(x.name == item.name || x.price == item.price)
{
if(item.count == 0)
{
break
}
else
{
self.basket.remove(at: counter)
self.updateBasket()
rowData.menuItems![flightIndex].count = rowData.menuItems![flightIndex].count-1;
self.table.reloadData()
break
}
}
counter = counter+1;
}
}
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let data = destinationData?[indexPath.row] {
// If user clicked last cell, do not try to access cell+1 (out of range)
if(indexPath.row + 1 >= (destinationData?.count)!) {
expandCell(tableView: tableView, index: indexPath.row)
}
else {
// If next cell is not nil, then cell is not expanded
if(destinationData?[indexPath.row+1] != nil) {
expandCell(tableView: tableView, index: indexPath.row)
} else {
contractCell(tableView: tableView, index: indexPath.row)
}
}
}
}
I dont really know how to solve this, all i know is that the plus function gets out of range on this bit "let data = rowData.menuItems![flightIndex]".
I am trying to make a numbered list out of the information the user inputs into a UITextView. For example,
List item one
List item two
List item three
Here is the code that I have tried but does not give me the desired effect.
var currentLine: Int = 1
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
// Add "1" when the user starts typing into the text field
if (textView.text.isEmpty && !text.isEmpty) {
textView.text = "\(currentLine). "
currentLine += 1
}
else {
if text.isEmpty {
if textView.text.characters.count >= 4 {
let str = textView.text.substring(from:textView.text.index(textView.text.endIndex, offsetBy: -4))
if str.hasPrefix("\n") {
textView.text = String(textView.text.characters.dropLast(3))
currentLine -= 1
}
}
else if text.isEmpty && textView.text.characters.count == 3 {
textView.text = String(textView.text.characters.dropLast(3))
currentLine = 1
}
}
else {
let str = textView.text.substring(from:textView.text.index(textView.text.endIndex, offsetBy: -1))
if str == "\n" {
textView.text = "\(textView.text!)\(currentLine). "
currentLine += 1
}
}
}
return true
}
as suggested here: How to make auto numbering on UITextview when press return key in swift but had no success.
Any help is much appreciated.
You can subclass UITextView, override method willMove(toSuperview and add an observer for UITextViewTextDidChange with a selector that break up your text into lines enumerating and numbering it accordingly. Try like this:
class NumberedTextView: UITextView {
override func willMove(toSuperview newSuperview: UIView?) {
frame = newSuperview?.frame.insetBy(dx: 50, dy: 80) ?? frame
backgroundColor = .lightGray
NotificationCenter.default.addObserver(self, selector: #selector(textViewDidChange), name: .UITextViewTextDidChange, object: nil)
}
func textViewDidChange(notification: Notification) {
var lines: [String] = []
for (index, line) in text.components(separatedBy: .newlines).enumerated() {
if !line.hasPrefix("\(index.advanced(by: 1))") &&
!line.trimmingCharacters(in: .whitespaces).isEmpty {
lines.append("\(index.advanced(by: 1)). " + line)
} else {
lines.append(line)
}
}
text = lines.joined(separator: "\n")
// this prevents two empty lines at the bottom
if text.hasSuffix("\n\n") {
text = String(text.characters.dropLast())
}
}
}
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let textView = NumberedTextView()
view.addSubview(textView)
}
}