What is the purpose of writing comments in Swift as:
// MARK: This is a comment
When you can also do:
// This is a comment
What does the // MARK achieve?
The // MARK: and // MARK: - syntax in Swift functions identically to the #pragma mark and #pragma mark - syntax in Objective-C.
When using this syntax (plus // TODO: and // FIXME:), you can get some extra information to show up in the quick jump bar.
Consider these few lines of source code:
// MARK: A mark comment lives here.
func isPrime(_ value: UInt) -> Bool { return true }
And for reference, the quick jump bar is at the top in Xcode:
It exists mostly to help with quick navigation within the file.
Note that the dash (// MARK: -) causes a nice separation line to show up. Consider this MARK comment:
// MARK: - A mark comment lives here.
The darker gray separator line just above the bolded option in that menu comes from the dash.
Additionally, we can achieve this separator line without a comment by simply not having any text after the dash:
// MARK: -
As mentioned, // TODO: and // FIXME: comments will also appear here.
// MARK: - Prime functions
func isPrime(_ value: UInt) -> Bool {
// TODO: Actually implement the logic for this method
return true
}
func nthPrime(_ value: UInt) -> Int {
// FIXME: Returns incorrect values for some arguments
return 2
}
FIXMEs get a little band-aid icon that help them standout.
MARK icon looks like a table of contents
TODO icons look more like a checklist
Clicking on any line in the quick jump bar takes you directly to that line in the source code.
MARK simply adds a visual MARK in the jump bar like this:
ex // MARK: Core Data Stack
Related
I have a basic Mac app with a standard NSTextView. I'm trying to implement and use a subclass of NSTextStorage, but even a very basic implementation breaks list editing behavior:
I add a bulleted list with two items
I copy & paste that list further down into the document
Pressing Enter in the pasted list breaks formatting for the last list item.
Here's a quick video:
Two issues:
The bullet points of the pasted list use a smaller font size
Pressing Enter after the second list item breaks the third item
This works fine when I don't replace the text storage.
Here's my code:
ViewController.swift
#IBOutlet var textView:NSTextView!
override func viewDidLoad() {
[...]
textView.layoutManager?.replaceTextStorage(TestTextStorage())
}
TestTextStorage.swift
class TestTextStorage: NSTextStorage {
let backingStore = NSMutableAttributedString()
override var string: String {
return backingStore.string
}
override func attributes(at location: Int, effectiveRange range: NSRangePointer?) -> [NSAttributedString.Key:Any] {
return backingStore.attributes(at: location, effectiveRange: range)
}
override func replaceCharacters(in range: NSRange, with str: String) {
beginEditing()
backingStore.replaceCharacters(in: range, with:str)
edited(.editedCharacters, range: range,
changeInLength: (str as NSString).length - range.length)
endEditing()
}
override func setAttributes(_ attrs: [NSAttributedString.Key: Any]?, range: NSRange) {
beginEditing()
backingStore.setAttributes(attrs, range: range)
edited(.editedAttributes, range: range, changeInLength: 0)
endEditing()
}
}
You have found a bug in Swift (and maybe not just in the Swift libraries, maybe in something a bit more fundamental).
So what is going on?
You will be able to see this a bit better if you create a numbered list rather than a bulleted one. You don't need to do any copy and paste, just:
Type "aa", hit return, type "bb"
Do select all and format as a numbered list
Place cursor at the end of "aa" and hit return...
What you see is a mess, but you can see the two original numbers are still there and the new middle list item you started by hitting return is where all the mess is.
When you hit return the text system has to renumber the list items, as you've just inserted a new item. First, it turns out that it performs this "renumbering" even if it is a bulleted list, which is why you see the mess in your example. Second, it does this renumbering by starting at the beginning of the list and renumbering every list item and inserting a new number for the just created item.
The Process in Objective-C
If you translate your Swift code into the equivalent Objective-C and trace through you can watch the process. Starting with:
1) aa
2) bb
the internal buffer is something like:
\t1)\taa\n\t2)\tbb
first the return is inserted:
\t1)\taa\n\n\t2)\tbb
and then an internal routine _reformListAtIndex: is called and it starts "renumbering". First it replaces \t1)\t with \t1) - the number hasn't changed. Then it inserts \t2)\t between the two new lines, as at this point we have:
\t1)\taa\n\t2)\t\n\t2)\tbb
and then it replaces the original \t2)\t with \t3)\t giving:
\t1)\taa\n\t2)\t\n\t3)\tbb
and it's job is done. All these replacements are based on specifying the range of characters to replace, the insertion uses a range of length 0, and go through:
- (void)replaceCharactersInRange:(NSRange)range withString:(NSString * _Nonnull)str
which in Swift is replaced by:
override func replaceCharacters(in range: NSRange, with str: String)
The Process in Swift
In Objective-C strings have reference semantics, change a string and all parts of the code with a reference to the string see the change. In Swift strings have value semantics and strings are copied (notionally at least) on being passed to functions etc.; if the copy is changed in called function the caller won't see that change in its copy.
The text system was written in (or for) Objective-C and it is reasonable to assume it may take advantage of the reference semantics. When you replace part of its code with Swift the Swift code has to do a little dance, during the list renumbering stage when replaceCharacters() gets called the stack will look something like:
#0 0x0000000100003470 in SwiftTextStorage.replaceCharacters(in:with:)
#1 0x0000000100003a00 in #objc SwiftTextStorage.replaceCharacters(in:with:) ()
#2 0x00007fff2cdc30c7 in -[NSMutableAttributedString replaceCharactersInRange:withAttributedString:] ()
#3 0x00007fff28998c41 in -[NSTextView(NSKeyBindingCommands) _reformListAtIndex:] ()
#4 0x00007fff284fd555 in -[NSTextView(NSKeyBindingCommands) insertNewline:] ()
Frame #4 is the Objective-C code called when return was hit, after inserting the newline it calls the internal routine _reformListAtIndex:, frame #3, to do the renumbering. This calls another Objective-C routine in frame #2, which in turn calls, frame #1, what it thinks is the Objective-C method replaceCharactersInRange:withString:, but is in fact a Swift replacement. This replacement does a little dance converting Objective-C reference semantic strings to Swift value semantics strings and then calls, frame #0, the Swift replaceCharacters().
Dancing is Hard
If you trace through your Swift code just as you did the Objective-C translation when the renumbering gets to the stage of changing the original \t2)\t to \t3)\t you will see a misstep, the range given for the original \t2)\t is what is was before the new \t2)\t was inserted in the previous step (i.e. it is off by 4 positions)... and you end up with a mess and a few more dance steps later the code crashes with a string referring error as the indices are all wrong.
This suggests that the Objective-C code is relying on reference semantics, and the choreographer of the Swift dance converting reference to value and back to reference semantics has failed to meet the Objective-C code's expectations: so either when the Objective-C code, or some Swift code which has replaced it, calculates the range of the original \t2)\t it is doing so on string which hasn't been altered by the previous insertion of the new \t2)\t.
Confused? Well dancing can make you dizzy at times ;-)
Fix?
Code your subclass of NSTextStorage in Objective-C and go to bugreport.apple.com and report the bug.
HTH (more than it makes you dizzy)
This question already has an answer here:
RxSwift/RxCocoa: prevent UITextField from having more than ... characters
(1 answer)
Closed 4 years ago.
I want to set a limit for characters in a textFiled using RxSwift,
may be i can benefit from Scan operator but i don't know how to use it in this case ,
I want my resulting code to behave as same as implementing it in shouldChangeCharacterInRage method:
func textField(_ textField: UITextField,
shouldChangeCharactersIn range: NSRange,
replacementString string: String)
-> Bool {
if textField == baseTextFiled{
let enteredString = (textField.text! as NSString).replacingCharacters(in: range, with: string)
if enteredString.count > limit{ // limit defined previously
return false
}
}
return true
}
Any help?
ReactiveX pushes data, so isn't really compatible with that particular delegate method. That said, you can still do it because .rx.text is a control property...
baseTextField.rx.text.orEmpty // pushes text
.map { String($0.prefix(limit)) } // pushes first X characters in text
.distinctUntilChanged() // only pushes if text is different than previously
.bind(to: baseTextField.rx.text) // pushes text into text field
.disposed(by: bag)
Per Wikipedia, Xcode defaults to using the K&R brace/indentation style. It looks like this:
- (void) someFunction {
if (condition) {
// do this
} else
// do that;
}
}
I've grown up with a strong preference for Allman style, which looks like this:
- (void) someFunction
{
if (condition)
{
// do this
}
else
{
// do that
}
}
It's not too much of a chore just to return the bracket of a code-completed statement to the next line, but if I could tell Xcode to do this for me, it would save me a lot of meticulous click-and-return'ing.
I don't think you can remove the K&R braced code snippets, but you could simply create your own Allman-style snippets and add them to the Xcode "Code Snippet Library". It's a cumbersome solution, but it works.
So, when writing your snippets, you can use the <# and #> to delimit your expressions. Thus:
if (<#condition#>)
{
<#statements-if-true#>
}
else
{
<#statements-if-false#>
}
Then drag and drop that onto your snippet library:
And give it a meaningful name and shortcut:
Now when you start typing, you'll leverage the new snippet:
Go ahead and give your snippet a unique completion shortcut if you want to make disambiguation even easier.
There are more effective uses of the snippet library, but it can be used to address your problem.
This is mostly for curiosity's sake. I've known for awhile that Xcode is capable of recognizing comments in the form of // TODO: Something I don't feel like doing now. Adding that line to the source of a file will cause that TODO comment to show up in Xcode's navigation bar:
I also recently discovered that comments of the form // MARK: Something can achieve the same effect as #pragma marking something. So I can write a comment that looks like:
// MARK: -
// MARK: Future Improvements:
// TODO: Make something better
// TODO: Fix some bug
And Xcode will render it out like this:
Which leads me to wonder: Are there other kinds of comments that Xcode can understand to improve project navigation?
There is also MARK, FIXME, !!! and ???, e.g.
// FIXME: this bug needs to be fixed
and
// ???: WTF ???
You can see where these are defined in /Applications/Xcode.app/Contents/OtherFrameworks/XcodeEdit.framework/Versions/A/Resources/BaseSupport.xclangspec (or /Developer/Library/PrivateFrameworks/XcodeEdit.framework/Resources/BaseSupport.xclangspec for older versions of Xcode). Presumably you could also add your own tags here if you wanted to but I have not actually tried this. Here is the relevant section in BaseSupport.xclangspec:
{
Identifier = "xcode.lang.comment.mark";
Syntax = {
StartChars = "MTF!?";
Match = (
"^MARK:[ \t]+\(.*\)$",
"^\(TODO:[ \t]+.*\)$", // include "TODO: " in the markers list
"^\(FIXME:[ \t]+.*\)$", // include "FIXME: " in the markers list
"^\(!!!:.*\)$", // include "!!!:" in the markers list
"^\(\\?\\?\\?:.*\)$" // include "???:" in the markers list
);
// This is the order of captures. All of the match strings above need the same order.
CaptureTypes = (
"xcode.syntax.mark"
);
Type = "xcode.syntax.comment";
};
},
These tags are also supported in the BBEdit text editor and its freeware sibling TextWrangler.
Looks like
// MARK:
// TODO:
// FIXME:
// ???:
// !!!:
all get translated into #pramga-like markers.
It appears that they stand for
// Mark, as in pragma
// To Do note
// Known bug marker
// Serious question about form, content, or function
// Serious concern about form, content, or function
You can use // MARK: - with tags below as per Apple example
// MARK: UICollectionViewDataSourcePrefetching
/// - Tag: Prefetching
For me, Visual Studio's Ctrl + K, Ctrl + C keyboard shortcut is used to comment-out the selected lines. When editing C++, this sometimes uses block comments (/* */) and sometimes uses line comments (//). Why does it change? How does it decide which to use when?
A couple other discussions on the topic:
Visual studio feature - commenting code Ctrl K - Ctrl C
visual studio C++ toggle comment ? comment while not whole line is selected?
Based on my own tinkerings, and what was said in those articles...
It's based on the start/end of the selection. It seems to use double slashes // whenever you start your selection at the beginning of the line AND end it at the end of a line.
It will use /* */ notation whenever the selection occurs midway through lines.
IE:
If I have the code
int main () {
return 0;
}
and highlight only int main, it will convert it to /*int main*/.
If I highlight the entire code section, starting after the indent tab, it will convert it to
/*int main () {
return 0;
}*/
But if I highlight the section starting before the indent tab, it converts it to
//int main () {
// return 0;
//}
Summary of links under Zhais' answer. Because following links is hard!
Selecting entire lines (including leading whitespace) will use //
Selecting at least one partial line
If a // comment is included, will use //
Otherwise, will use /* */