Way to remove all -viewDidUnload from project's view controllers - ios

As Apple's Official Doc said:
-viewDidUnload is deprecated in iOS 6.0. Views are no longer purged under low-memory conditions and so this method is never called.
Meanwhile, it's better to remove all -viewDidUnload implements from projects that the deployment target is iOS 6.0 or later. But removing it one by one is boring, especially you've hundreds of controllers & several projects.
So, is there any script or command that can do this batch job?

I figured out a command for Vim, I'm sure it'll make your life easier. ;)
Open Vim in desired root dir (generally, it'll be your root dir of your all controller files), press Shift : to enter command-line mode, run the command below:
:args **/*.m | argdo %s/^-\ (void)viewDidUnload\_.\{-}}\n^$\n//ge | update
This will replace all
- (void)viewDidUnload
{
[super viewDidUnload];
...
}
// a blank line here
to empty, in other words, the -viewDidUnload snippet will be removed. But note, there's a blank line after the implement. If you don't want to include it, use
:args **/*.m | argdo %s/^-\ (void)viewDidUnload\_.\{-}}//ge | update
instead.
Note: This will include lib files as well when you're in your project's root dir. I suggest go to your Controllers' root dir, then all files & you will be happy with the result. ;)
Tip:
After that, you'd better check whether all -viewDidUnload were removed, run the command below on terminal of your desired root dir:
$ find . -type f -iname "*.m" -exec grep -i "viewDidUnload" {} +
It should result with no output. Otherwise, some targets missed, you can locate it easily cause it'll list all files that not managed correctly, then just remove it manually (This might happen if your - (void)viewDidLoad is -(void)viewDidLoad without a space, or something else).
Finally, you can run
$ git diff -b --color-words
to see the result. Enjoy it! ;)
Further reading about the command
args **/*.m: Sets arglist to contain all .m files in current directory and it's subdirectories;
argdo: Run the following command(s) on all arguments in arglist;
%s/^-\ (void)viewDidUnload\_.\{-}}\n^$\n//ge: Vim RegEx to replace -viewDidUnload implement snippet to empty;
\_.: Find any character including end-of-line (linebreak).
\{-}: Match as few as possible (stopping at the first }, e.g. \{-}h will stop at the first h);
}: The last item to match;
\n: Line-break;
^$\n: blank line.
update: Save modification only if the buffer has been modified.
Reference
Search Across Multiple Lines
Search and Replace in Multiple Buffers

Related

post-build event with multiple if/copy combinations only execute if first file does not exist

Given the bin\ directory inside the Delphi project contains the files Cert.pem and Key.pem, the below Delphi post-build event only copies both files if C:\Binaries\Cert.pem does not exist:
if not exist $(OUTPUTDIR)Cert.pem (copy bin\Cert.pem $(OUTPUTDIR))
if not exist $(OUTPUTDIR)Key.pem (copy bin\Key.pem $(OUTPUTDIR))
As soon as C:\Binaries\Cert.pem exists, the Key.pem file is never copied.
How can I solve this in the post-build event?
Edit: unlike my 2014 post, this is indeed possible using parentheses. See my answer below.
The problem with Delphi post-build events is that they are not batch files.
It means that statements that look like lines are being concatenated by the Delphi IDE into one big & ampersand separated statement. This ensures the commands are executed in sequence, as per Command Redirection, Pipes - Windows CMD - SS64.com:
commandA & commandB Run commandA and then run commandB
So this is the actual statement that gets executed:
if not exist $(OUTPUTDIR)Cert.pem (copy bin\Cert.pem $(OUTPUTDIR))&if not exist $(OUTPUTDIR)Key.pem (copy bin\Key.pem $(OUTPUTDIR))
The problem here is that now the second if is seen as a continuation of the "then" part of the first if statement: the second if never executes when the $(OUTPUTDIR)Cert.pem exists.
What helps is a little known feature that you can wrap each command inside parentheses. Normally this is to allow one command to span multiple lines (especially for if, and for..do loops), but it also works on one line.
Wrapping each line having an if statement inside parentheses ensures they become standalone statements not affecting the other lines, even if they are being concatenated with & ampersand separators.
In the dialog it looks like this:
(if not exist $(OUTPUTDIR)Cert.pem (copy bin\Cert.pem $(OUTPUTDIR)))
(if not exist $(OUTPUTDIR)Key.pem (copy bin\Key.pem $(OUTPUTDIR)))
That way, the IDE translates it into one statement:
(if not exist $(OUTPUTDIR)Cert.pem (copy bin\Cert.pem $(OUTPUTDIR)))&(if not exist $(OUTPUTDIR)Key.pem (copy bin\Key.pem $(OUTPUTDIR)))
Now it works as intended:
When $(OUTPUTDIR)Cert.pem exists but $(OUTPUTDIR)Key.pem does not, only $(OUTPUTDIR)Cert.pem is copied
When $(OUTPUTDIR)Cert.pem does exists but $(OUTPUTDIR)Key.pem does, only $(OUTPUTDIR)Key.pem is copied
when neither exist, both are copied
when both exist, neither are copied
I did not know this "trick" when writing my 2014 post Delphi prebuild/prelink/postbuild events, so I need to write an update for it.
Searching for batch file parentheses site:microsoft.com -site:social.technet.microsoft.com -site:answers.microsoft.com did not reveal it in the official documentation, but I am not surprised as it grew hysterically, instead of being designed. Or like the Old New Thing attributes h2g2:
Much like the universe, if anyone ever does fully come to understand Batch then the language will instantly be replaced by an infinitely weirder and more complex version of itself. This has obviously happened at least once before ;)
The best documentation I could find was at Parenthesis/Brackets - Windows CMD - SS64.com:
Parenthesis can be used to split commands across multiple lines. This can make code more readable. Variables will be evaluated for the code block just as if the command was a single line.
(command)
(
command
command )
Things that break inside parenthesis
The CMD shell does not use any great intelligence when evaluating parenthesis, so for example the command below will fail:
IF EXIST MyFile.txt (ECHO Some(more)Potatoes)
...
Use multiple build events instead of putting both commands in the same event.
Executing the source lines of a build event.
I can cut this short very easily: build events are not batch files.
What happens is that all lines in your build event are concatenated together using ampersand (&) signs which are used to execute multiple commands on one command line.
This means that all the fancy control structures (if statements, setlocal, for loops) are not possible inside build events.
ref: Pasted from a blog post: Delphi prebuild/prelink/postbuild events written by Jeroen W. Pluimers
Makes me wonder why you asked since it looks like you wrote the answer in 2014. :)

Search for files that contain pattern

I have this search - I would like to print out the paths of files that contain the matching text:
grep -r "jasmine" .
and it yields results that look like this:
./app-root/runtime/repo/node_modules/jasmine-core/.github/CONTRIBUTING.md:- [Jasmine Google Group](http://groups.google.com/group/jasmine-js)
./app-root/runtime/repo/node_modules/jasmine-core/.github/CONTRIBUTING.md:- [Jasmine-dev Google Group](http://groups.google.com/group/jasmine-js-dev)
./app-root/runtime/repo/node_modules/jasmine-core/.github/CONTRIBUTING.md:git clone git#github.com:yourUserName/jasmine.git # Clone your fork
./app-root/runtime/repo/node_modules/jasmine-core/.github/CONTRIBUTING.md:cd jasmine # Change directory
./app-root/runtime/repo/node_modules/jasmine-core/.github/CONTRIBUTING.md:git remote add upstream https://github.com/jasmine/jasmine.git # Assign original repository to a remote named 'upstream'
./app-root/runtime/repo/node_modules/jasmine-core/.github/CONTRIBUTING.md:Note that Jasmine tests itself. The files in `lib` are loaded first, defining the reference `jasmine`. Then the files in `src` are loaded, defining the reference `j$`. So there are two copies of the code loaded under test.
./app-root/runtime/repo/node_modules/jasmine-core/.github/CONTRIBUTING.md:The tests should always use `j$` to refer to the objects and functions that are being tested. But the tests can use functions on `jasmine` as needed. _Be careful how you structure any new test code_. Copy the patterns you see in the existing code - this ensures that the code you're testing is not leaking into the `jasmine` reference and vice-versa.
But I just want the file names, I don't want to print out the matching contents, just the file names, how can I do that?
The problem is that the matching text will wrap around in the terminal and make the results basically unreadable.
Did you use the -l flag from grep?
-l, --files-with-matches
Suppress normal output; instead print the name of each input file from which output would normally have been printed. The scanning will stop on the first match.
A simple search on my home directory,
grep -rl 'bash' .
./.bashrc
./.bash_history
./.bash_logout
./.bash_profile
./.profile
./.viminfo
As a matter of fact, -l is a POSIX defined option for grep should be available in almost all distros.

Finding a file in the User Library of OS X Yosemite

I wish to find a file in the lower levels of the OS X file system (Below where Spotlight searches) by content.
In other words: I know the sting abc12345 os in a text file someplace.
It could be in /Library or perhaps /Users/joe/Library or even /Users/joe/Library/Caches
How does one file the file?
I.m not sure how to use grep (or even if it the appropriate tool for the job)
Humor a newbee to the command line?
In Terminal, type
find $HOME -type f -exec grep "abc12345" {} \+
That says... starting in your HOME directory, find all things that are files (not directories) and look inside them for the string "abc12345" and print anything you find. The \+ at the end says to look in several files in one go, rather than one at a time.
If you want to read all about the find command, or any other command, type find in the Terminal, put your mouse over the word and right click, then left-click Open man Page.

Is there a way to show custom warnings when building a project in XCode?

Let's say I want to detect something in my code which I cannot check by tests.
e.g.:
- Go over my entire code base to detect there I have a space between brackets and curly brackets (using a regex).
- Go over my entire code base and detect style smells.
etc...
If one of these checks fails, I'd like to show a custom warning I define myself.
Is there anything like this in XCode?
Thanks.
I wrote a run script for Xcode that does exactly what you requested. It searches by regex for predefined "code smells" or "style smells" and warns you at compile time
Read the blog post, but the final script is here
#test if git exists.
command -v git > /dev/null 2>$1 || {exit 0}
#separate code smells with | i.e. (code_smell_1|code_smell_2)
KEYWORDS="(didDeselectRowAtIndexPath)"
git diff --name-only HEAD | grep "\.m" | xargs egrep -s --with-filename --line-number --only-matching "$KEYWORDS.*[^\/]*$" | perl -p -e "s/($KEYWORDS)/ warning: Are you sure you want to use \$1?\nTo remove this warning, append a comment at the end of this line \$1/"
This particular script searches for appearances of didDeselectRowAtIndexPath in the code, but you can change that to any string
You would need to create a project target that runs a script, which searches through your source files and does your checks (this is not trivial) and returns non-zero to indicate error.
Then make your app target dependent on this "check target" and the build will fail if the check fails.
If you want some indication of how you write this "check script" then I would be inclined to employ the clang static analyzer. However, unfortunately, scan-build is not installed as part of the Xcode Command Line tools, so you would need to use the LLVM-binaries in some way, or perhaps the macports version contains it.
For trivial checks, relating to spaces and other stylistic issues rather than real, live, code problems, then you will have to employ some other mechanism, and I have no idea how to start with that, sorry.

ack misses results (vs. grep)

I'm sure I'm misunderstanding something about ack's file/directory ignore defaults, but perhaps somebody could shed some light on this for me:
mbuck$ grep logout -R app/views/
Binary file app/views/shared/._header.html.erb.bak.swp matches
Binary file app/views/shared/._header.html.erb.swp matches
app/views/shared/_header.html.erb.bak: <%= link_to logout_text, logout_path, { :title => logout_text, :class => 'login-menuitem' } %>
mbuck$ ack logout app/views/
mbuck$
Whereas...
mbuck$ ack -u logout app/views/
Binary file app/views/shared/._header.html.erb.bak.swp matches
Binary file app/views/shared/._header.html.erb.swp matches
app/views/shared/_header.html.erb.bak
98:<%= link_to logout_text, logout_path, { :title => logout_text, :class => 'login-menuitem' } %>
Simply calling ack without options can't find the result within a .bak file, but calling with the --unrestricted option can find the result. As far as I can tell, though, ack does not ignore .bak files by default.
UPDATE
Thanks to the helpful comments below, here are the new contents of my ~/.ackrc:
--type-add=ruby=.haml,.rake
--type-add=css=.less
ack is peculiar in that it doesn't have a blacklist of file types to ignore, but rather a whitelist of file types that it will search in.
To quote from the man page:
With no file selections, ack-grep only searches files of types that it recognizes. If you have a file called foo.wango, and ack-grep doesn't know what a .wango file is, ack-grep won't search it.
(Note that I'm using Ubuntu where the binary is called ack-grep due to a naming conflict)
ack --help-types will show a list of types your ack installation supports.
If you are ever confused about what files ack will be searching, simply add the -f option. It will list all the files that it finds to be searchable.
ack --man states:
If you want ack to search every file,
even ones that it always ignores like
coredumps and backup files, use the
"−u" switch.
and
Why does ack ignore unknown files by
default? ack is designed by a
programmer, for programmers, for
searching large trees of code. Most
codebases have a lot files in them
which aren’t source files (like
compiled object files, source control
metadata, etc), and grep wastes a lot
of time searching through all of those
as well and returning matches from
those files.
That’s why ack’s behavior of not
searching things it doesn’t recognize
is one of its greatest strengths: the
speed you get from only searching the
things that you want to be looking at.
EDIT: Also if you look at the source code, bak files are ignored.
Instead of wrestling with ack, you could just use plain old grep, from 1973. Because it uses explicitly blacklisted files, instead of whitelisted filetypes, it never omits correct results, ever. Given a couple of lines of config (which I created in my home directory 'dotfiles' repo back in the 1990s), grep actually matches or surpasses many of ack's claimed advantages - in particular, speed: When searching the same set of files, grep is faster than ack.
The grep config that makes me happy looks like this, in my .bashrc:
# Custom 'grep' behaviour
# Search recursively
# Ignore binary files
# Output in pretty colors
# Exclude a bunch of files and directories by name
# (this both prevents false positives, and speeds it up)
function grp {
grep -rI --color --exclude-dir=node_modules --exclude-dir=\.bzr --exclude-dir=\.git --exclude-dir=\.hg --exclude-dir=\.svn --exclude-dir=build --exclude-dir=dist --exclude-dir=.tox --exclude=tags "$#"
}
function grpy {
grp --include=*.py "$#"
}
The exact list of files and directories to ignore will probably differ for you: I'm mostly a Python dev and these settings work for me.
It's also easy to add sub-customisations, as I show for my 'grpy', that I use to grep Python source.
Defining bash functions like this is preferable to setting GREP_OPTIONS, which will cause ALL executions of grep from your login shell to behave differently, including those invoked by programs you have run. Those programs will probably barf on the unexpectedly different behaviour of grep.
My new functions, 'grp' and 'grpy', deliberately don't shadow 'grep', so that I can still use the original behaviour any time I need that.

Resources