'advanced(by:)' is unavailable convert from swift 3 to swift 4 - xcode

internal func rangeFromNSRange(_ nsRange: NSRange) -> Range<String.Index>? {
let from16 = utf16.startIndex.advanced(by: nsRange.location)
let to16 = from16.advanced(by: nsRange.length) //advanced(by:) is unavailable
if let from = String.Index(from16, within: self),
let to = String.Index(to16, within: self) {
return from ..< to
}
return nil
}
I have this file in swift 3 and I'm trying to convert it to swift 4 but I get this error and also this error
public func height(_ width: CGFloat, font: UIFont, lineBreakMode: NSLineBreakMode?) -> CGFloat {
var attrib: [String: AnyObject] = [NSAttributedStringKey.font.rawValue: font]
if lineBreakMode != nil {
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineBreakMode = lineBreakMode!
attrib.updateValue(paragraphStyle, forKey: NSAttributedStringKey.paragraphStyle.rawValue)
}
let size = CGSize(width: width, height: CGFloat(Double.greatestFiniteMagnitude))
return ceil((self as NSString).boundingRect(with: size, options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes:attrib, context: nil).height)
}
// Cannot convert value of type '[String : AnyObject]' to expected argument type '[NSAttributedStringKey : Any]?'

In Swift 4 there is an API to make Range<String.Index> from NSRange and vice versa. The String extension can be reduced to
internal func range(from nsRange: NSRange) -> Range<String.Index>? {
return Range(nsRange, in: self)
}
In Swift 4 the type of string attributes has been changed from String to NSAttributedStringKey. For example NSForegroundColorAttributeName is replaced with NSAttributedStringKey.foregroundColor. You need to change the declaration of attrib to
var attrib: [NSAttributedStringKey: Any] = [.font: font]
and to change the line to add an attribute accordingly.

Related

call child data from firebase

Good evening,
I am trying to call data to post onto a card very similar to tinder. When I run my code, everything works and I see the print statement in the console. However the card view shows a default image with default text.
I was wondering if anyone has encountered this issue and could possibly help explain what I am doing wrong.
fileprivate func fetchUsersFromDatabase() {
Database.database().reference().child("JobPost").observeSingleEvent(of: .value, with: {(Snapshot) in
if let eachDict = Snapshot.value as? NSDictionary{
for each in eachDict{
//I think the issue is caused by the let post = poster
let post = Poster(dictionary: Snapshot.value as! [String : Any])
self.cardViewModels.append(post.toCardViewModel())
print(each.value )
}
}
self.setupDummyCards()
}, withCancel: {(Err) in
})
}
// the struct is in an extension file.
struct Poster: ProducesCardViewModel{
var jobName : String?
var price: Int?
var postName: String?
var ImageUrl1: String?
var uid: String?
init(dictionary: [String: Any]) {
self.price = dictionary["cost"] as? Int
self.jobName = dictionary["category"] as? String
self.postName = dictionary["description"] as? String ?? ""
self.ImageUrl1 = dictionary["JobImageUrl"] as? String ?? ""
self.uid = dictionary["fromId"] as? String ?? ""
}
func toCardViewModel() -> CardViewModel {
let attributedText = NSMutableAttributedString(string: jobName ?? "", attributes: [.font: UIFont.systemFont(ofSize: 32, weight: .heavy)])
let priceString = price != nil ? "\(price!)" : "N\\A"
attributedText.append(NSAttributedString(string: " \(priceString)", attributes: [.font: UIFont.systemFont(ofSize: 24, weight: .regular)]))
let jobString = jobName != nil ? jobName! : "Not available"
attributedText.append(NSAttributedString(string: "\n\(jobString)", attributes: [.font: UIFont.systemFont(ofSize: 20, weight: .regular)]))
return CardViewModel(imageNames: [ImageUrl1 ?? "" ], attributedString: attributedText, textAlignment: .left)
}
}
Example
// toCardViewModel
import UIKit
protocol ProducesCardViewModel {
func toCardViewModel() -> CardViewModel
}
class CardViewModel {
let JobimageName: [String]
let attributedString: NSAttributedString
let textAlignment: NSTextAlignment
init(imageNames: [String], attributedString: NSAttributedString, textAlignment: NSTextAlignment) {
self.JobimageName = imageNames
self.attributedString = attributedString
self.textAlignment = textAlignment
}
fileprivate var imageIndex = 0 {
didSet {
let imageName = JobimageName[imageIndex]
let image = UIImage(named: imageName)
imageIndexObserver?(imageIndex, image)
}
}
var imageIndexObserver: ((Int, UIImage?) -> ())?
func advanceToNextPhoto() {
imageIndex = min(imageIndex + 1, JobimageName.count - 1)
}
func goToPreviousPhoto() {
imageIndex = max(0, imageIndex - 1)
}
}
Thank you in advance!
// P.S I previously posted this question without lack of sufficient detail. I decided to just re post it with the quality material. I really appreciate your time.
I have figured out an answer and it was quite obvious to me. I noticed that
print(each.value )
would print the value, so I just substituted
let post = Poster(dictionary: Snapshot.value as! [String : Any])
to
let post = Poster(dictionary: each.value as! [String : Any])
and everything started to work just fine!

How do you get text length in Swift 4?

I am not sure how to update this code:
func textWidth(text: String, font: UIFont?) -> CGFloat
{
let attributes = font?.fontDescriptor.fontAttributes
return text.size(withAttributes: attributes).width
}
Swift 4 complain:
Cannot convert value of type '[UIFontDescriptor.AttributeName : Any]?' to expected argument type '[NSAttributedStringKey : Any]?'
I don't know why they broke this, but it does not get automatically fixed.
(SWIFT 4 Updated)
func textWidth(text: String, font: UIFont?) -> CGFloat {
let attributes = font != nil ? [NSFontAttributeName: font] : [:]
return text.size(withAttributes: attributes).width
}
Hope it helps.
I guess, you want to write something like this:
(Swift 4)
func textWidth(text: String, font: UIFont?) -> CGFloat {
let attributes = font != nil ? [NSAttributedStringKey.font: font!] : [:]
return text.size(withAttributes: attributes).width
}
(Swift 3)
func textWidth(text: String, font: UIFont?) -> CGFloat {
let attributes = font != nil ? [NSFontAttributeName: font!] : [:]
return text.size(attributes: attributes).width
}
fontAttributes is not a valid input for size(withAttributes:) (size(attributes:) in Swift 3) even if the type matches.
An alternative way to do this in Swift 4, avoiding the handling of the optional, is like this:
extension UIFont {
func textWidth(s: String) -> CGFloat
{
return s.size(withAttributes: [NSAttributedStringKey.font: self]).width
}
}

Saved Parse Database into an array called recipes and am now trying to access content within that array

I have a database in parse that i have pulled into a swift array. The custom parse object is called UserRecipe. The array is called recipes and is located in the viewDidLoad method. I am trying to set the imageview i have called recipeImage, to always access the image of the first element in the array. I do this in the updateImage function but am not sure if I have the correct syntax. Also the array seems to be stored only with the viewDidLoad method and is not accessible to my updateImage function. I'm wondering how to make it global so all functions can access it. Thanks in advance for any help.
The database looks like this:
import UIKit
import Parse
//import ParseFacebookUtilsV4
import FBSDKCoreKit
import FBSDKLoginKit
class ViewController: UIViewController {
let recipes = [PFObject]?.self
#IBOutlet var recipeImage: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
//load in all data from Parse custom Object UserRecipe and store it in variable recipes
var query = PFQuery(className:"UserRecipe")
query.findObjectsInBackgroundWithBlock {
(recipes: [PFObject]?, error: NSError?) -> Void in
if error == nil {
if let recipes = recipes {
for recipe in recipes {
print(recipe["recipeName"])
}
}
} else {
print("Error: \(error!) \(error!.userInfo)")
}
}
let gesture = UIPanGestureRecognizer(target: self, action: Selector("wasDragged:"))
recipeImage.addGestureRecognizer(gesture)
//let tapping = UITapGestureRecognizer(target: self, action: Selector("wasTapped:"))
//recipeImage.addGestureRecognizer(tapping)
recipeImage.userInteractionEnabled = true
//updateImage()
//getUserInfo()
}
func wasDragged(gesture: UIPanGestureRecognizer) {
//Dragging Animation
let translation = gesture.translationInView(self.view)
let imageDrag = gesture.view!
imageDrag.center = CGPoint(x: self.view.bounds.width / 2 + translation.x, y: self.view.bounds.height / 2 + translation.y - 153)
let xFromCenter = imageDrag.center.x - self.view.bounds.width / 2 + translation.x
let scale = min(100 / abs(xFromCenter), 1)
var rotation = CGAffineTransformMakeRotation(xFromCenter / 200)
var stretch = CGAffineTransformScale(rotation, scale, scale)
imageDrag.transform = stretch
//determines whether current user has accepted or rejected certain recipes
if gesture.state == UIGestureRecognizerState.Ended {
var acceptedOrRejected = ""
if imageDrag.center.x < 100 {
acceptedOrRejected = "rejected"
print("not chosen")
//print("not chosen" + object["recipeName"])
} else if imageDrag.center.x > self.view.bounds.width - 100 {
acceptedOrRejected = "accepted"
print("Chosen")
}
/*if acceptedOrRejected != "" {
PFUser.currentUser()?.addUniqueObjectsFromArray([displayedUserId], forKey: acceptedOrRejected)
PFUser.currentUser()?.saveInBackgroundWithBlock({
(succeeded: Bool, error: NSError?) -> Void in
if succeeded {
} else {
print(error)
}
})
}*/
//Resets image position after it has been let go of
rotation = CGAffineTransformMakeRotation(0)
stretch = CGAffineTransformScale(rotation, 1, 1)
imageDrag.transform = stretch
imageDrag.center = CGPoint(x: self.view.bounds.width / 2, y: self.view.bounds.height / 2 - 153)
updateImage()
}
}
func updateImage() {
recipeImage.image = recipes["image"][0]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I am not across Parse but if I were you these are things I would try,
Set a breakpoint in
func updateImage() {
// set breakpoint here and check whether recipes contains any data.
recipeImage.image = recipes["image"][0]
}
Replace the code as shown below,
//replace
recipes["image"][0]
//to
recipes[0]["image"]

How to get filename last photo in Swift 2.0 iOS9?

I want to get file_name (example = IMG_xxxx.jpg)
func lastphoto() {
var fetchOptions: PHFetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: true)]
var fetchResult = PHAsset.fetchAssetsWithMediaType(PHAssetMediaType.Image, options: fetchOptions)
if (fetchResult.lastObject != nil) {
var lastAsset: PHAsset = fetchResult.lastObject as! PHAsset
let options:PHImageRequestOptions = PHImageRequestOptions()
options.version = PHImageRequestOptionsVersion.Current
PHImageManager.defaultManager().requestImageForAsset(lastAsset,
targetSize: self.imageView.bounds.size,
contentMode: PHImageContentMode.AspectFill,
options: PHImageRequestOptions(),
resultHandler: { (result, info) -> Void in
self.imageView.image = result
let manager = PHImageManager.defaultManager()
let assets = PHAsset.fetchAssetsWithMediaType(.Image, options: nil)
})
}
}
As of iOS 9.0, you can get the original file name using the following:
var filename: String?
if #available(iOS 9.0, *) {
let resources = PHAssetResource.assetResourcesForAsset(lastAsset)
if let resource = resources.first {
filename = resource.originalFilename
}
}
If you're supporting pre-iOS 9.0 versions, you can also try using an undocumented workaround that still works as of iOS 9.1:
filename = lastAsset.valueForKey("filename") as? String

errors while trying to compare a string to element in array

let verbList: [String] = ["hacer", "ser", "estar"]
let POVList: [String] = ["él / usted","ella / usted","ellas / ustedes","ellos / ustedes","tú","yo","nosotros",]
let correctConjugation: [[String]] = [["hace","hace","hacen","hacen","haces","hago","hacemos"], ["es","es","son","son","eres","soy","somos"], ["está","está","estan","estan","estas","estoy","estamos"]]
func randomVerb() -> Int { //creates and returns a random number for the prefix arrray
var randomVerb = Int(arc4random_uniform(3))
return randomVerb
}
func randomPrefix() -> Int { //creates and returns a random number for the verb array
var randomPrefix = Int(arc4random_uniform(7))
return randomPrefix
}
#IBAction func changeVerb(sender: AnyObject) {
Verb.text = verbList[randomVerb()]
POV.text = POVList[randomPrefix()]
userResponse.backgroundColor = UIColor.whiteColor()
userResponse.text = ""
}
#IBAction func checkResponse(sender: AnyObject) {
var userResponseA: String
userResponseA = userResponse.text
if (userResponseA == correctConjugation[randomVerb()[randomPrefix()]]){
userResponse.backgroundColor = UIColor.greenColor()
} else {
userResponse.backgroundColor = UIColor.redColor()
}
}
So I get two errors here (in the if statement in checkResponse): first, "int does not have a member named 'subscript'" and if I just take out the call for the function in the if statement I get: "'String' is not convertible to 'Mirror Disposition'"
I really have no idea why this is not working. Bear with me, as I am an Xcode noob just trying to get a better grade in spanish.
Very close - just need to have your subscripts separated:
if (userResponseA == correctConjugation[randomVerb()][randomPrefix()]) {
// ...
}
When working with an array of arrays (in this case correctConjugation), each subscript takes you one level down.
For the other issue, you want a couple variables to hold the current verb and prefix indexes:
class VC: UIViewController {
// list declarations here
var verbIndex = 0
var povIndex = 0
#IBAction func changeVerb(sender: AnyObject) {
verbIndex = randomVerb()
povIndex = randomPrefix()
Verb.text = verbList[verbIndex]
POV.text = POVList[povIndex]
userResponse.backgroundColor = UIColor.whiteColor()
userResponse.text = ""
}
#IBAction func checkResponse(sender: AnyObject) {
var userResponseA = userResponse.text
if (userResponseA == correctConjugation[verbIndex][povIndex]){
userResponse.backgroundColor = UIColor.greenColor()
} else {
userResponse.backgroundColor = UIColor.redColor()
}
}
}

Resources