#nsrange
Explore tagged Tumblr posts
Text
Convert NSRange from Range before Swift 4
let str = "Hello, playground! Hello, world! Hello, earth!" let attributedString = NSAttributedString(string: str) attributedString.enumerateAttributes(in: NSRange(location: 0, length: str.characters.count), options: NSAttributedString.EnumerationOptions.longestEffectiveRangeNotRequired) { (attributes, range, stop) in }
In order to have a smoother migration from now to Swift 4. Let's create a grammar compatible function to convert NSRange from Range before Xcode 9 is released officially.
extension NSRange { init(_ range: Range<String.Index>, in string: String) { self.init() let startIndex = range.lowerBound.samePosition(in: string.utf16) let endIndex = range.upperBound.samePosition(in: string.utf16) self.location = string.distance(from: string.startIndex, to: range.lowerBound) self.length = startIndex.distance(to: endIndex) } }
And now, we are able to do conversion like this NSRange(range, in: "A string"). Let's do an experiment. The following processes are trying to convert range0: Range -> range1: Range -> range2: NSRange.
let str = "Hello, playground! Hello, world! Hello, earth!" let range0 = str.range(of: "playground") print(String(describing: type(of: range0))) let range1 = NSRange(range0!, in: str) print(String(describing: type(of: range1))) let start = range1.location let end = start + range1.length let range2 = Range(uncheckedBounds: (start, end)) print(String(describing: type(of: range2)))
0 notes
Text
Spell Checker iOS Tutorial
The UITextChecker object can be used to spell-check a string. In this tutorial a few words will be displayed inside a Table View. When the words are selected, they will be checked for spelling, the background color will change to green if the spelling is correct, otherwise the background color will change to red. This tutorial is made in Xcode 10 and built for iOS 12.
Open Xcode and create a new Single View Application. For product name, use IOSSpellingCheckerTutorial and then fill out the Organization Name and Organization Identifier with your customary values. Enter Swift as Language and choose Next.
Remove the View Controller from the Storyboard and drag a Navigation Controller to the empty canvas. This will also include a Table view Controller. When the initial View Controller is deleted there isn't a starting point defined. Select the Navigation Controller and go to the Attribute Inspector. In the View Controller Section select the "Is Initial View Controller" checkbox.
Double-click on the Navigation Bar in The Table View Controller and set the title to "Choose the correct spelling". Select the Table View Cell and go to the Attributes Inspector. In the Table View Cell section set the Identifier to "Cell".
The Storyboard should look like this.
Since we have deleted the View Controller from the Storyboard we can also delete the ViewController.swift file. Add a new file to the project, select iOS->Source->Cocoa Touch Class. Name it TableViewController and make it a subclass of UITableViewController.
The TableViewController class needs to be linked to The Table View Controller object in the Storyboard. Select it and go the Identity Inspector. In the Custom Class section change the class to TableViewController
..
Go to the TableViewController.swift file and add the following property
let words = ["devalopment", "development","devellopment"]
This array of strings will be displayed inside the Table View. Next, alter the predefined delegate methods.
override func numberOfSections(in tableView: UITableView) -> Int { return 1 } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return words.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) cell.textLabel?.text = words[indexPath.row] cell.textLabel?.backgroundColor = UIColor.clear return cell }
The Table View has one section and three rows from the words array. The background color of the cell will be set to a clear color, because later on the background color of the cell will be changed. When the user selects a row from the Table View the tableView(_:didSelectRowAtIndexPath:) delegate method will be called.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { if let cell = tableView.cellForRow(at: indexPath) { let currentWord = cell.textLabel?.text if let currentWord = currentWord { if wordIsSpelledCorrect(word: currentWord) { cell.backgroundColor = UIColor.green } else { cell.backgroundColor = UIColor.red } tableView.reloadData() } } }
The word from the selected cell will be checked for spelling. If this word is spelled correctly. the cell's background will be green, otherwise it will be red. The actual spelling checker will be done in the wordIsSpelledCorrect method.
func wordIsSpelledCorrect(word: String) -> Bool { let checker = UITextChecker() let range = NSRange(location: 0, length: word.count) let wordRange = checker.rangeOfMisspelledWord(in: word, range: range, startingAt: 0, wrap: false, language: "en") return wordRange.location == NSNotFound }
The UITextChecker class can be used to check a string for the right spelling. a range is created which include the whole word. The rangeOfMisspelledWord(in:range:startingAt:wrap:language:) method is used to check the range for errors. If a word is spelled correctly a NSNotFound is returned from this method so the return value will be a boolean with the value of true, otherwise the value will be false.
Build and Run the project, select the rows, if the word is spelled correctly the background color will change to green. otherwise it is misspelled and the background color will change to red.
You can download the source code of the IOSSpellingCheckerTutorial at the ioscreator repository on Github.
0 notes
Text
watchOS 4 Tutorial Part 3: Animation
Update Note: This tutorial has been updated to Swift 4/watchOS 4 by Audrey Tam. The original tutorial was written by Mic Pringle.
Welcome back to our watchOS 4 tutorial series!
In the first part of this series, you learned about the basics of watchOS 4 development by creating your first interface controller.
In the second part of the series, you learned how to add tables to your app.
In this third part of the series, you’ll learn how to use watchOS 4 animations by adding a new check-in interface to your app.
In the process, you’ll learn:
How to create image-based animations.
How to use the watchOS 4 animation API.
And with that, let’s get cracking! ┗(°0°)┛
Note: This tutorial picks up where we left things off in Part 2 of this series. You can either continue with the same project, or download it here, if you want to start fresh.
Getting Started
Open Watch\Interface.storyboard, and drag an interface controller from the Object Library onto the storyboard canvas. With the interface controller selected, open the Attributes inspector, and set Identifier to CheckIn. You do this so you can present the interface controller from within ScheduleInterfaceController.
Next, drag a group onto the new interface controller from the Object Library. Use the Attributes inspector to make the following changes:
Set Layout to Vertical.
Set Mode to Center.
Set the Horizontal Alignment to Center.
Set Height to Relative to Container.
Your interface controller should now look like this:
Next, you’ll build the same label-image-label group that you created for the table row.
Drag another group into the existing group, and make the following changes using the Attributes inspector:
Set Spacing to 4.
Set the Horizontal Alignment to Center.
Set Width to Size To Fit Content.
Set Height to Fixed, with a value of 30 (a little shorter than the table row).
Add a label and an image to this new layout group. You’ll configure the label, then copy and update it, to display the origin and destination of each flight.
Select the image, either in the storyboard or in the document outline. Using the Attributes inspector, make the following changes:
Set Image to Plane.
Set Tint to #FA114F (our pink, again!).
Set Vertical Alignment to Center.
Set Width to Fixed, with a value of 24.
Set Height to Fixed, with a value of 20.
As before, the image isn’t tinted, so you can’t see it against the black background of the interface controller. But you know it’s there.
Select the label, and set its Text to MEL. Next, change its Font to System, with a style of Semibold and a size of 20. Finally, set its Vertical alignment to Center, and check that its Width and Height are both Size To Fit Content.
Copy the label, then paste it next to the image. Change its text to SFO and its Horizontal Alignment to Right. Your interface controller should now look like the following:
Now it’s time to add a huge check-in button!
Adding the Check-In Button
Drag a button from the Object Library onto the interface controller, making sure it’s positioned as a sibling of the group containing the origin and destination labels:
Buttons in WatchKit are incredibly flexible; you can use them with their stock appearance – the way the one you just added looks – or you can turn them into a layout group, and add other interface objects to customize their appearance. That’s exactly what you’re going to do here.
Select the button, and use the Attributes inspector to make the following changes:
Set Content to Group.
Set the Horizontal Alignment to Center.
Set the Vertical Alignment to Center.
Your interface controller should now look like this:
You may have noticed when you changed the Content attribute of the button, a new group appeared in the document outline:
This is what you’re going to use as the background of your custom check-in button. Select this group, and use the Attributes inspector to make the following changes:
Set Color to #FA114F.
Set Radius to 39.
Set Width to Fixed, with a value of 78.
Set Height to Fixed, with a value of 78.
The interface controller should now look like this:
Your check-in button is really starting to take shape. The only thing missing is the label, so you’ll add that next.
Drag a label from the Object Library into the group belonging to the button, and then select it. Once again, make the following changes, using the Attributes inspector:
Set Text to Check In.
Set Font to System, with a style of Semibold and a size of 16.
Set the Horizontal Alignment to Center.
Set the Vertical Alignment to Center.
Your finished check-in interface controller should now look like this:
With the interface complete, it’s now time to create a subclass of WKInterfaceController to manage this controller, and to update ScheduleInterfaceController to show it.
Creating the Controller
Right-click on the Watch Extension group in the Project navigator and choose New File…. In the dialog that appears, select watchOS\Source\WatchKit Class, and click Next. Name the new class CheckInInterfaceController, and make sure it’s subclassing WKInterfaceController, and that Language is set to Swift:
Click Next, and then Create.
When the new file opens in the code editor, delete the three empty method stubs, so you’re left with just the import statements and the class definition.
Next, add the following to the top of the class:
@IBOutlet var backgroundGroup: WKInterfaceGroup! @IBOutlet var originLabel: WKInterfaceLabel! @IBOutlet var destinationLabel: WKInterfaceLabel!
Here, you’re simply adding outlets for the outer-most group and the two labels of the interface you just created. You’ll hook everything up soon.
Next, add the following just below the outlets:
var flight: Flight? { didSet { guard let flight = flight else { return } originLabel.setText(flight.origin) destinationLabel.setText(flight.destination) } }
You know the score by now! Here, you’ve added an optional property of type Flight, which includes a property observer. When the observer is fired, you try to unwrap flight, and if successful, use flight to configure the two labels. This is all familiar territory now, right?
Now you just need to set flight when the controller is presented. Add the following to CheckInInterfaceController:
override func awake(withContext context: Any?) { super.awake(withContext: context) if let flight = context as? Flight { self.flight = flight } }
Again, this should be super familiar by now. You try to unwrap and cast context to an instance of Flight. If that succeeds, you use it to set self.flight, which in turn, triggers the property observer configuring the interface.
Finally, add the following action just below awake(withContext:):
@IBAction func checkInButtonTapped() { // 1 let duration = 0.35 let delay = DispatchTime.now() + (duration + 0.15) // 2 backgroundGroup.setBackgroundImageNamed("Progress") // 3 backgroundGroup.startAnimatingWithImages(in: NSRange(location: 0, length: 10), duration: duration, repeatCount: 1) // 4 DispatchQueue.main.asyncAfter(deadline: delay) { [weak self] in // 5 self?.flight?.checkedIn = true self?.dismiss() } }
Here’s the play-by-play of what’s happening:
You create two constants: one for the duration of the animation and one for the delay after which the controller will be dismissed. Instead of being a Double, delay is an instance of DispatchTime, since you’ll be using it with Grand Central Dispatch.
You load a sequence of images named Progress, and set them as the background image of backgroundGroup. Layout groups conform to WKImageAnimatable, which allows you to use them to play back animated image sequences.
You begin playback of the image sequence. The range you supply covers the entire sequence, and a repeatCount of 1 means the animation will play just once.
WatchKit doesn’t have completion handlers, so you use Grand Central Dispatch to execute the closure after the given delay.
In the closure, you mark flight as checked-in, and then dismiss the controller.
Now you just need to add the images to the project, and hook up the outlets and single action.
Download this zip file, unzip the file, and drag the folder into your Watch\Assets.xcassets.
Make sure you drag the folder, not its contents. This should create a new group in the asset catalog called Progress, containing several image sets:
With the images in place, it’s time to set up the outlets and button action.
Open Watch\Interface.storyboard, and select your new interface controller. In the Identity inspector, change Custom Class\Class to CheckInInterfaceController:
Next, in the document outline, right-click on CheckIn to invoke the outlets and actions popup. Connect backgroundGroup to the outer-most group in the interface controller:
In the storyboard canvas, connect destinationLabel to the label containing SFO, and connect originLabel to the label containing MEL.
Next, connect checkInButtonTapped to the big, round, pink button:
Before you build and run, the final change you need to make is to actually present this interface controller.
Presenting the Controller
Open ScheduleInterfaceController.swift, find table(_:didSelectRowAt:), and replace its contents with the following:
let flight = flights[rowIndex] let controllers = ["Flight", "CheckIn"] presentController(withNames: controllers, contexts: [flight, flight])
Here, you retrieve the appropriate flight from flights using rowIndex, create an array containing the identifiers of the two interface controllers you want to present, and then present them, passing flight as the context to both.
Build and run. Tap a flight, and you’ll see a pair of interface controllers are presented. Swipe left to reveal the check-in controller, then tap the button to trigger the animation and check-in:
This looks great as-is, but it’d be even better if checked-in flights were highlighted on the schedule interface controller, as well. You’ll address that in the next, and final, section.
Highlighting the Flight
Open FlightRowController.swift, and add the following method to it:
func updateForCheckIn() { let color = UIColor(red: 90/255, green: 200/255, blue: 250/255, alpha: 1) planeImage.setTintColor(color) separator.setColor(color) }
Here, you’re creating an instance of UIColor, then using it to set the tint color and color of planeImage and separator, respectively. This method will be called from within an animation closure, so the color change will animate nicely.
Next, open ScheduleInterfaceController.swift, and add the following property below flights:
var selectedIndex = 0
You’ll use this to remember which table row was selected when presenting the two interface controllers. Now you just need to set it when a table row is selected. Add the following just above the call to presentController(withNames:contexts:) in table(_:didSelectRowAt:):
selectedIndex = rowIndex
This sets selectedIndex to the index of the selected table row.
Finally, add the following to ScheduleInterfaceController, just below awake(withContext:):
override func didAppear() { super.didAppear() // 1 guard flights[selectedIndex].checkedIn, let controller = flightsTable.rowController(at: selectedIndex) as? FlightRowController else { return } // 2 animate(withDuration: 0.35) { // 3 controller.updateForCheckIn() } }
Here’s what’s happening in the code above:
You check to see if the selected flight is checked-in. If so, you try to cast the row controller, at the corresponding index in the table, to an instance of FlightRowController.
If that succeeds, you use the animation API on WKInterfaceController to execute the given closure, over a duration of 0.35 second.
In the closure, you call the method you just added to FlightRowController, which changes the color of the plane image and separator of that table row, and provides users with some visual feedback that they’re now checked-in.
Build and run. Follow the same steps as before to check-in for a flight, and you’ll see that when you’re returned to the schedule interface controller, the colors of the plane image and separator on the corresponding table row crossfade to a new color:
Congratulations! You’ve now finished implementing your very first set of WatchKit animations.
Where to Go From Here?
Here is the finished example project from this tutorial series.
In this tutorial you’ve learned how to create two different kinds of WatchKit animation. The first, using an animated sequence of images, and the second, using the animation API on WKInterfaceController. You’re now suitably primed to add plenty of visual flair to your own watchOS 4 apps!
Sadly, this is where we end this tutorial series.
If you have any questions or comments on this tutorial, please join the forum discussion below! :]
If you enjoyed this tutorial series, you’d definitely enjoy our book watchOS by Tutorials.
The book goes into further detail on making watchOS apps and is written for intermediate iOS developers who already know the basics of iOS and Swift development but want to learn how to make Apple Watch apps for watchOS 4.
It’s been fully updated for Swift 4, watchOS 4 and Xcode 8 — get it on the raywenderlich.com store today!
The post watchOS 4 Tutorial Part 3: Animation appeared first on Ray Wenderlich.
watchOS 4 Tutorial Part 3: Animation published first on http://ift.tt/2fA8nUr
0 notes
Text
325. Maximum Size Subarray Sum Equals k
https://leetcode.com/problems/maximum-size-subarray-sum-equals-k/description/
加密题目- Facebook 常考题目
Given an array nums and a target value k, find the maximum length of a subarray that sums to k. If there isn't one, return 0 instead.
Note: The sum of the entire nums array is guaranteed to fit within the 32-bit signed integer range.
Example 1:
Given nums = [1, -1, 5, -2, 3], k = 3, return 4. (because the subarray [1, -1, 5, -2] sums to 3 and is the longest)
Example 2:
Given nums = [-2, -1, 2, 1], k = 1, return 2. (because the subarray [-1, 2] sums to 1 and is the longest)
Follow Up: Can you do it in O(n) time?
思路: 一开始想了个 两边删除的算法。然后就超时了。不过也有点小意思~就是range 的通用写法就是 left 包括 right 不包括。这样code 比较规范简单 NSRange 也是这么定义的。
后来用了Hashmap,这个跟 2sum 一个意思不过呢。更要巧妙点。一个for index ++, 然后每一个从0 开始的sum 的最远的 index 放在 dictionary 里面。。。处理上注意dummy code for 空left sum。
Swift 注意 optional unwrapping。 还有就是dict的用法 , such as
if (dict[key] != nil) { let v = dict[key]! .....}
class Solution { func maxSubArrayLenNaive(_ nums: [Int], _ k: Int) -> Int { let sum = nums.reduce(0,+) var sumleft = [Int]() var sumright = [Int]()
sumleft.append(0) sumright.append(sum) for x in nums{ sumleft.append(sumleft[sumleft.count-1] + x) sumright.append(sumright[sumright.count-1] - x) }
var maxlen = 0 for lefti in 0..<nums.count{ for righti in 1...nums.count{ //print("left\(lefti):right\(righti)") let ssum = sum - sumleft[lefti] - sumright[righti] if ssum == k { maxlen = max(righti-lefti, maxlen ) } } } return maxlen }
func maxSubArrayLen(_ nums: [Int], _ k: Int) -> Int {
var ans = 0 var subsum = 0 // var dict = [Int:Int]() // dict[0] = -1 var dict = [0:-1] // 等于以上两行,而且这是dummy node for i in 0..<nums.count{ subsum += nums[i] if dict[subsum] == nil {// 这里很重要,就是记录最远的 i dict[subsum] = i } if dict[subsum-k] != nil { // subsum-k 不是 k-subsum ans = max(ans, i - dict[subsum-k]!) } } return ans } }
0 notes
Text
Find and return the ranges of all the occurrences of a given string in Swift
Return the first occurrence multiple times to collect all occurrences
If you look up Apple Developer Documentation, you will find the description of function range(of:options:range:locale:) which is identical to the quote below.
Finds and returns the range of the first occurrence of a given string within a given range of the String, subject to given options, using the specified locale, if any.
Yes, it only returns the first occurrence. Therefore, to fulfill our purpose, we need to construct a while-loop to iterate all the occurrences of a given string within the receiver. A reference snippet will be like the following code block. And note that an offset is also added to reduce the length of range in each iteration. So actually, the position of each loop is basically based on the upper bound of the previous iteration.
extension String { func indices(of occurrence: String) -> [Int] { var indices = [Int]() var position = startIndex while let range = range(of: occurrence, range: position..<endIndex) { let i = distance(from: startIndex, to: range.lowerBound) indices.append(i) let offset = occurrence.distance(from: occurrence.startIndex, to: occurrence.endIndex) - 1 guard let after = index(range.lowerBound, offsetBy: offset, limitedBy: endIndex) else { break } position = index(after: after) } return indices } }
Transform indices to ranges
In applying above code to a real case, sometimes returning all indices is not enough to do find-and-replace-all operations in text editing. Therefore, a transform helper can help to generate a range array that is much easier to deal with substrings.
extension String { func ranges(of searchString: String) -> [Range<String.Index>] { let _indices = indices(of: searchString) let count = searchString.characters.count return _indices.map({ index(startIndex, offsetBy: $0)..<index(startIndex, offsetBy: $0+count) }) } }
Create NSRange from Range before Swift 4
If you have shifted your Xcode to version 9. The Swift standard library of Swift 4 provides a method to convert from Range<String.Index> to NSRange directly. It’s definitely a feature that many developers are looking forward to it because it’s still unavoidable to deal with NSRange sometimes when certain function calls are not fully migrated to native Swift yet, like an example of NSAttributedString below.
let str = "Hello, playground! Hello, world! Hello, earth!" let attributedString = NSAttributedString(string: str) attributedString.enumerateAttributes(in: NSRange(location: 0, length: str.utf16.count), options: NSAttributedString.EnumerationOptions.longestEffectiveRangeNotRequired) { (attributes, range, stop) in }
In order to have a smoother migration from the current version of Swift to Swift 4. We can implement a grammar compatible function to create NSRange from Range before Xcode 9 is released officially.
extension NSRange { init(_ range: Range<String.Index>, in string: String) { self.init() let startIndex = range.lowerBound.samePosition(in: string.utf16) let endIndex = range.upperBound.samePosition(in: string.utf16) self.location = string.distance(from: string.startIndex, to: range.lowerBound) self.length = startIndex.distance(to: endIndex) } }
Test above functions in the playground
Basically, all above codes are necessary elements we need to find and return the ranges of all the occurrences of a given string. Last, let's test and see a result by the snippet below.
let str = "Hello, playground, Hello, playground, Hello, playground, Hello, playground, Hello, playground" let indices = str.indices(of: "round") print("[Int] : \(indices)") let ranges = str.ranges(of: "playground") for range in ranges { print("`Range` : " + str.substring(with: range)) } for range in ranges.map({ NSRange($0, in: str) }) { print("`NSRange` : " + (str as NSString).substring(with: range)) }
And the log console will be seen like this in the playground.
[Int] : [12, 31, 50, 69, 88] `Range` : playground `Range` : playground `Range` : playground `Range` : playground `Range` : playground `NSRange` : playground `NSRange` : playground `NSRange` : playground `NSRange` : playground `NSRange` : playground
0 notes
Text
String or NSString, which one ought to be
Use native types whenever possible
In general, you should use the Swift native types as possible as you can because they are optimized to compile for better performance. But wait, I just said unavoidable, right? Let's take a look at an Objective-C based class NSRegularExpression as an example.
let str = "Hello, playground" do { let expression = try NSRegularExpression(pattern: "\\s{1,}", options: [.anchorsMatchLines]) let range = NSRange(location: 0, length: str.characters.count) let matches = expression.matches(in: str, options: [], range: range) for match in matches { print(match) } } catch { print(error.localizedDescription) }
In above snippet, we can see the function func matches(in string: String, options: NSRegularExpression.MatchingOptions = [], range: NSRange) -> [NSTextCheckingResult] which only accepts NSRange variable as a parameter; therefore, translating Range type str.startIndex..<str.endIndex to NSRange class will be undoubtedly necessary once we have our codes interoperate and be mixed up String, NSString, Range and NSRange. However, an experienced Swift programmer might find there is a lethal flaw in above snippet also. It's about the way of calculating string length, str.characters.count. The practice like this is highly error prone because Swift uses Extended Grapheme Clusters. Ex, a Unicode smiley symbol. Swift sees it as one character, but the NSString method sees it as two.
So... is there a principal or suggestion?
If we don't want to pay too much attention to the difference like above example, for risk-free, my suggestion is always to cast String to NSString once facing Objective-C based function, like NSRegularExpression. Of course, the strategy will not be necessary until native Swift function is introduced, ex. we might see RegularExpression someday. So, in order to fix above flaw. The way to calculate length should be like the snippet below. All in all, there are always native ways to deal with variables; however, a risk-free or less error prone strategy can save us a day sometimes :)
// Option 1: Cast String to NSString let range = NSRange(location: 0, length: (str as NSString).length) // Option 2: Calculate utf16 count when accessing on a Swift String value. let range = NSRange(location: 0, length: str.utf16.count)
0 notes