欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

iOS通過shell腳本批量修改屬性

 更新時(shí)間:2018年03月04日 18:32:34   作者:aron1992  
這篇文章主要給大家分享了iOS通過shell腳本批量修改屬性的相關(guān)知識(shí)點(diǎn),希望我們整理的內(nèi)容能夠幫助到大家。

背景

公司需要做一系列的殼版本,殼版本如果內(nèi)容雷同提交到App Store會(huì)有被拒絕的風(fēng)險(xiǎn),除了我在上一篇文章中說道的在殼版本中注入混淆的代碼,防止被蘋果檢測(cè)到內(nèi)容太過雷同而導(dǎo)致審核被拒絕。還有另一種可行的方法是批量修改源文件中的類名、屬性、方法名稱等會(huì)在二進(jìn)制文件中留下符號(hào)標(biāo)記的信息,繞過蘋果的機(jī)器審核。
這篇文章介紹的是如何使用腳本批量修改屬性名稱,后續(xù)還有系列的包括使用腳本批量修改類名稱、方法名稱等信息的文章。

結(jié)果

下面是執(zhí)行腳本替換了屬性的結(jié)果圖,腳本把所有需要替換的屬性添加了abc后綴,當(dāng)然依然是可以正常編譯運(yùn)行的

源碼:https://gitee.com/dhar/YTTInjectedContentKit

分析

原理分析

objc代碼中的類名、屬性、方法、源文件路徑等信息最終會(huì)被打包到二進(jìn)制文件中,保存在二進(jìn)制文件中的.sym符號(hào)表段中,可以使用objdump -t命令查看二進(jìn)制符號(hào)信息,以下的命令把objdump -t的結(jié)果寫入到文件InjectedContentKit_Example_Symbols中去。

objdump -t InjectedContentKit_Example > InjectedContentKit_Example_Symbols

文件的內(nèi)容會(huì)很大,所以選擇了幾個(gè)代表性的內(nèi)容說明:

0000000100026350 l d __TEXT,__text	__text
# 這里保存的是類源文件的路徑符號(hào)信息
0000000000000000 l d *UND*	/Users/aron/PuTaoWorkSpace/project/sscatch/DevPods/InjectedContentKit/InjectedContentKit/Classes/Composer/PubSearchDataComposer.h

# 這里保存的是屬性對(duì)應(yīng)的var信息
0000000000000000 l d *UND*	_OBJC_IVAR_$_TextCardItem._title
0000000000000000 l d *UND*	_OBJC_IVAR_$_TextCardItem._showReact
0000000000000000 l d *UND*	_OBJC_IVAR_$_TextCardItem._topChart
0000000000000000 l d *UND*	_OBJC_IVAR_$_TextCardItem._reaction

# 這里保存的是屬性信息對(duì)應(yīng)的getter方法信息
00000001000264a0 l  F __TEXT,__text	-[TextCardItem title]
00000001000264c0 l  F __TEXT,__text	-[TextCardItem showReact]
00000001000264f0 l  F __TEXT,__text	-[TextCardItem topChart]
0000000100026510 l  F __TEXT,__text	-[TextCardItem setTopChart:]

# 這里保存的是屬性信息對(duì)應(yīng)的setter方法信息
00000001000028a0 l  F __TEXT,__text	-[SSCatchInviteScheduler setOrganizer:]
00000001000028e0 l  F __TEXT,__text	-[SSCatchInviteScheduler setInputCardBack:]
0000000100002920 l  F __TEXT,__text	-[SSCatchInviteScheduler setInputTextBack:]

# 這里保存的是類文件的文件名信息
0000000000000000 l d *UND*	PubSearchDataComposer.m
000000005a937587 l d __TEXT,__stub_helper	__stub_helper
00000001000251c0 l d __TEXT,__text	__text

從上面可以看出,二進(jìn)制中保留了很多信息和源代碼有很大關(guān)系,我們做個(gè)簡單的猜測(cè)蘋果后臺(tái)機(jī)器審查二進(jìn)制的時(shí)候會(huì)通過二進(jìn)制中的符號(hào)進(jìn)行對(duì)比,如果兩個(gè)二進(jìn)制(一個(gè)主版本、一個(gè)殼版本)代碼中的符號(hào)重合度超過某個(gè)閾值,就會(huì)判定這是發(fā)布?xì)ぐ姹镜男袨?,而這是蘋果說不允許的,所以可行的方法是修改源文件中的這些信息來繞過蘋果的審查機(jī)制。

另外猜測(cè)蘋果應(yīng)該是不會(huì)根據(jù)代碼中的流程控制來判斷的,因?yàn)槎M(jìn)制中的控制流程已經(jīng)是機(jī)器碼了,反編譯出來也就是匯編代碼,只要稍微做點(diǎn)改動(dòng)二進(jìn)制(.text段)就會(huì)變化很大。所以從這個(gè)方面來判斷就難度很大了。

步驟分析

主要有以下幾個(gè)步驟

  1. 尋找到需要替換的源文件中的所有的屬性,處理之后保存在配置文件中
  2. 用戶自定義一個(gè)黑名單配置文件
  3. 某部分需要隔離的代碼中的屬性生成黑名單配置文件
  4. 把需要替換的源文件中的所有匹配的屬性做批量的替換

這里說明下為什么第一步需要保存在配置文件中,因?yàn)榈谌降牟僮饔胁糠趾偷谝徊绞窍嗤?,所有這部分單獨(dú)出來一個(gè)模塊共用,都是輸入一個(gè)文件夾,最終保存在指定的文件中,后面的代碼中可以看到這部分。

實(shí)現(xiàn)

單步實(shí)現(xiàn)

1、尋找到需要替換的源文件中的所有的屬性,處理之后保存在配置文件中

這一步的功能是客戶端輸入一個(gè)需要處理的源碼文件夾,遞歸遍歷該源碼文件夾獲取所有源碼文件(.h .m 文件)。使用正則匹配找到屬性名稱,暫時(shí)保存到數(shù)組中,最后經(jīng)過黑名單過濾、去重過濾、其他過濾條件過濾,最終把待處理的屬性保存到客戶端輸入的輸出文件中。

可以分解為一下幾個(gè)小步驟

  • 遞歸遍歷文件夾獲取源碼文件
  • 正則匹配源碼文件的屬性
  • 過濾屬性(可選)
  • 保存屬性到文件

這部分功能的源碼如下:

文件名: GetAndStoreProperties.sh

該腳本在多個(gè)地方都有用到,所以作為一個(gè)單獨(dú)的模塊,定義了一些參數(shù),以適應(yīng)不同的應(yīng)用場景。在下面可以看到使用該腳本的地方。

#!/bin/bash
########################
# 腳本功能:從指定目錄獲取和保存屬性到指定的文件
# 輸入?yún)?shù) -i 輸入的文件夾
# 輸入?yún)?shù) -o 保存的文件
# 輸入?yún)?shù) -f 使用黑名單和自定義過濾條件的參數(shù)
# 輸入?yún)?shù) -c 自定義的黑名單文件
########################

####### 參數(shù)定義
param_input_dir=""
param_output_file=""
param_custom_filter_file=""
param_should_use_filter=0

####### 參數(shù)解析
while getopts :i:o:c:f opt
do
	case "$opt" in
		i) param_input_dir=$OPTARG
			echo "Found the -i option, with parameter value $OPTARG"
			;;
		o) param_output_file=$OPTARG
			echo "Found the -o option, with parameter value $OPTARG"
			;;
		c) param_custom_filter_file=$OPTARG
			echo "Found the -c option, with parameter value $OPTARG"
			;;
		f) echo "Found the -f option" 
			param_should_use_filter=1
			;;
		*) echo "Unknown option: $opt";;
	esac
done


####### 配置

# 屬性黑名單配置文件
blacklist_cfg_file="$(pwd)/DefaultBlackListPropertiesConfig.cfg"

####### 數(shù)據(jù)定義

# 定義保存源文件的數(shù)組
declare -a implement_source_file_array
implement_source_file_count=0


# 定義保存屬性的數(shù)組
declare -a tmp_props_array
props_count=0


# mark: p384
# 遞歸函數(shù)讀取目錄下的所有.m文件
function read_source_file_recursively {
	echo "read_implement_file_recursively"
	if [[ -d $1 ]]; then
		for item in $(ls $1); do
			itemPath="$1/${item}"
			if [[ -d $itemPath ]]; then
				# 目錄
				echo "處理目錄 ${itemPath}"
				read_source_file_recursively $itemPath
				echo "處理目錄結(jié)束====="
			else 
				# 文件
				echo "處理文件 ${itemPath}"
				if [[ $(expr "$item" : '.*\.m') -gt 0 ]] || [[ $(expr "$item" : '.*\.h') -gt 0 ]]; then
					echo ">>>>>>>>>>>>mmmmmmm"
					implement_source_file_array[$implement_source_file_count]=${itemPath}
					implement_source_file_count=$[ implement_source_file_count + 1 ];
				fi
				echo ""
			fi
		done
	else
		echo "err:不是一個(gè)目錄"
	fi
}


# 讀取源碼中的屬性,保存到數(shù)組中
# 參數(shù)一: 源碼文件路徑
function get_properties_from_source_file {
	local class_file=$1;
	echo "class_file=${class_file}"

	properties=$(grep "@property.*" ${class_file})
	IFS_OLD=$IFS
	IFS=$'\n'
	for prop_line in $properties; do
		echo ">>>>>${prop_line}"

		asterisk_seperator_pattern="\*"
		if [[ ${prop_line} =~ ${asterisk_seperator_pattern} ]]; then
			# 從左向右截取最后一個(gè)string后的字符串
			prop_name=${prop_line##*${asterisk_seperator_pattern}}
			# 從左向右截取第一個(gè)string后的字符串
			seal_pattern=";*"
			seal_pattern_replacement=""
			prop_name=${prop_name//${seal_pattern}/${seal_pattern_replacement}}
			subsring_pattern="[ |;]"
			replacement=""
			prop_name=${prop_name//${subsring_pattern}/${replacement}}

			if [[ ${param_should_use_filter} -gt 0 ]]; then
				grep_result=$(grep ${prop_name} ${blacklist_cfg_file})
				echo "grep_result = >>${grep_result}<<"
				custom_grep_result=""
				if [[ -n ${param_custom_filter_file} ]]; then
					custom_grep_result=$(grep ${prop_name} ${param_custom_filter_file})
				fi
				if [[ -n ${grep_result} ]] || [[ -n ${custom_grep_result} ]]; then
					echo "--${prop_name}--存在配置文件中"
				else
					echo "--${prop_name}--XXX不存在配置文件中"

					tmp_props_array[$props_count]=$prop_name
					props_count=$[ props_count + 1 ]
					echo ">>>>>>>result_prop_name=${prop_name}"
				fi
			else
				tmp_props_array[$props_count]=$prop_name
				props_count=$[ props_count + 1 ]
			fi			
		fi
	done
	IFS=$IFS_OLD
}

# 獲取目錄下的所有源文件,讀取其中的屬性
function get_properties_from_source_dir {

	local l_classed_folder=$1

	echo "獲取需要處理的源文件... ${l_classed_folder}"
	# 讀取需要處理目標(biāo)文件
	read_source_file_recursively ${l_classed_folder}

	echo "讀取源文件中的屬性..."
	for(( i=0;i<${#implement_source_file_array[@]};i++)) 
	do 
		class_file=${implement_source_file_array[i]}; 
		echo "處理源文件:${class_file}"
		get_properties_from_source_file ${class_file}
	done;
}

# 把獲取到的屬性過濾之后寫入文件中
# 過濾步驟包含去重、去掉簡單詞匯、去掉長度少于多少的詞匯
# 如果在執(zhí)行的過程中遇到特殊情況,添加到黑名單配置(DefaultBlackListPropertiesConfig.cfg文件中添加配置)
function post_get_properties_handle {

	local prop_config_file=$1

	# 寫入文件中
	echo "# Properties Configs" > ${prop_config_file}
	for key in $(echo ${!tmp_props_array[*]})
	do
	 # echo "$key : ${tmp_props_array[$key]}"
	 echo ${tmp_props_array[$key]} >> ${prop_config_file}
	done

	# 去重
	cfg_back_file="${prop_config_file}.bak"
	mv ${prop_config_file} ${cfg_back_file}
	sort ${cfg_back_file} | uniq > ${prop_config_file}
	
	# 過濾
	if [[ ${param_should_use_filter} -gt 0 ]]; then
		mv ${prop_config_file} ${cfg_back_file}
		echo "# Properties Configs Filtered" > ${prop_config_file}
		IFS_OLD=$IFS
		IFS=$'\n'
		# 上一行的內(nèi)容
		lastLine="";
		for line in $(cat ${cfg_back_file} | sed 's/^[ \t]*//g')
		do
			if [[ ${#line} -le 6 ]] || [[ $(expr "$line" : '^#.*') -gt 0 ]]; then
				# 長度小于等于6或者注釋內(nèi)容的行不處理
				echo "less then 6 char line or comment line"
			else
				if [[ -n ${lastLine} ]]; then
					# 上一行是非空白行
					# 比較上一行內(nèi)容是否是當(dāng)前行的一部分,不是添加上一行
					if [[ ${line} =~ ${lastLine} ]]; then
						echo "${line} 和 ${lastLine} 有交集"
					else
						echo ${lastLine} >> ${prop_config_file}
					fi
				fi
				# 更新上一行
				lastLine=${line}
			fi	
		done
		IFS=${IFS_OLD}
	fi

	# 刪除臨時(shí)文件
	rm -f ${cfg_back_file}
}


get_properties_from_source_dir ${param_input_dir}
post_get_properties_handle ${param_output_file}

使用以上腳本生成的配置文件 PropertiesConfigs.cfg 部分如下:

# Properties Configs Filtered
UserRestrictionLabel
aboutusButton
activitySamplers
addAddressPress
addressSamplers
addressTextBox
appealPress
appliedGroupedSamplers
appliedSamplers
applyPress
asyncArray
asyncListSampler
audioPlayer

2. 用戶自定義一個(gè)黑名單配置文件

在實(shí)踐的過程中,替換屬性的符號(hào)有時(shí)候會(huì)把系統(tǒng)類的屬性替換了,比如

  • 把 AppDelegate 中的 window 屬性替換了,導(dǎo)致了編譯鏈接沒錯(cuò),但是界面出不來了,因?yàn)槌跏嫉膚indow對(duì)象找不到了
  • 把 UIButton 中的 titleLabel 屬性替換了,直接導(dǎo)致了編譯出錯(cuò)

對(duì)于這類問題,需要在黑名單中配置一些默認(rèn)的過濾屬性,對(duì)于黑名單中的這些屬性不處理即可,在我的業(yè)務(wù)場景下,黑名單文件的配置如下:

文件名:DefaultBlackListPropertiesConfig.cfg

# BlackListPropertiesConfig.cfg
# 屬性黑名單配置,在此配置文件中的屬性不需要替換名稱
window
name
title
titleLabel
layout
appealSamplers

在 GetAndStoreProperties.sh 腳本使用到的代碼片段如下,其實(shí)就是使用了 grep 命來查找,判斷時(shí)候有找到,如果有就不處理,具體的可以看上面提供的完整的 GetAndStoreProperties.sh 腳本代碼

if [[ ${param_should_use_filter} -gt 0 ]]; then
	grep_result=$(grep ${prop_name} ${blacklist_cfg_file})
	echo "grep_result = >>${grep_result}<<"
	custom_grep_result=""
	if [[ -n ${param_custom_filter_file} ]]; then
		custom_grep_result=$(grep ${prop_name} ${param_custom_filter_file})
	fi
	if [[ -n ${grep_result} ]] || [[ -n ${custom_grep_result} ]]; then
		echo "--${prop_name}--存在配置文件中"
	else
		echo "--${prop_name}--XXX不存在配置文件中"

		tmp_props_array[$props_count]=$prop_name
		props_count=$[ props_count + 1 ]
		echo ">>>>>>>result_prop_name=${prop_name}"
	fi
else
	tmp_props_array[$props_count]=$prop_name
	props_count=$[ props_count + 1 ]
fi	

3. 某部分需要隔離的代碼中的屬性生成黑名單配置文件

這部分的功能其實(shí)就是調(diào)用 GetAndStoreProperties.sh 這個(gè)腳本,最終把文件輸出的文件以追加的方式寫入到用戶自定義的黑名單屬性文件中。

#...
# 黑名單類目錄
declare -a custom_blacklist_search_dirs
custom_blacklist_search_dirs=("/Users/aron/PuTaoWorkSpace/project/sscatch/sscatch/Classes/SSCatchAPI" 
	"/Users/aron/PuTaoWorkSpace/project/sscatch/sscatch/Classes/Categories" 
	"/Users/aron/PuTaoWorkSpace/project/sscatch/sscatch/Classes/Components" 
	"/Users/aron/PuTaoWorkSpace/project/sscatch/sscatch/Classes/External" 
	"/Users/aron/PuTaoWorkSpace/project/sscatch/sscatch/Classes/HandyTools" 
	"/Users/aron/PuTaoWorkSpace/project/sscatch/sscatch/Classes/Macros" )
# ...

# 屬性黑名單配置文件
custom_blacklist_cfg_file="$(pwd)/CustomBlackListPropertiesConfig.cfg"

# ...
# 獲取自定義的黑名單屬性并保存到文件中
echo "" > ${custom_blacklist_cfg_file}
for (( i = 0; i < ${#custom_blacklist_search_dirs[@]}; i++ )); do
	custom_blacklist_search_dir=${custom_blacklist_search_dirs[${i}]}
	./GetAndStoreProperties.sh \
		-i ${custom_blacklist_search_dir}\
		-o ${custom_blacklist_cfg_tmp_file}
	cat ${custom_blacklist_cfg_tmp_file} >> ${custom_blacklist_cfg_file}
done
#...

最終生成的用戶自定義的黑名單文件部分如下

文件:CustomBlackListPropertiesConfig.cfg

# Properties Configs
DBFilePath
ValidityString
accessQueue
age
attributedNameString
avatarURLString
avatarUrlString
backColorString
bodyScheduler
bodyView
catchDateString
cellHeight
channelKey
cityName
conditionString
# ....

4. 把需要替換的源文件中的所有匹配的屬性做批量的替換

這一步在前面三部的基礎(chǔ)上,查找并替換源碼目錄中在 PropertiesConfigs.cfg 配置文件中出現(xiàn)的屬性和屬性的引用,查找使用grep命令、替換使用了sed命令。腳本代碼如下

#!/bin/bash
# 屬性重命名腳本

####### 配置
# classes類目錄
classes_dir="$(pwd)/../InjectedContentKitx"
# 黑名單類目錄
declare -a custom_blacklist_search_dirs
custom_blacklist_search_dirs=("/Users/aron/PuTaoWorkSpace/project/sscatch/sscatch/Classes/SSCatchAPI" 
	"/Users/aron/PuTaoWorkSpace/project/sscatch/sscatch/Classes/Categories" 
	"/Users/aron/PuTaoWorkSpace/project/sscatch/sscatch/Classes/Components" 
	"/Users/aron/PuTaoWorkSpace/project/sscatch/sscatch/Classes/External" 
	"/Users/aron/PuTaoWorkSpace/project/sscatch/sscatch/Classes/HandyTools" 
	"/Users/aron/PuTaoWorkSpace/project/sscatch/sscatch/Classes/Macros" )
# 配置文件
cfg_file="$(pwd)/PropertiesConfigs.cfg"
# 屬性黑名單配置文件
blacklist_cfg_file="$(pwd)/DefaultBlackListPropertiesConfig.cfg"
# 屬性黑名單配置文件
custom_blacklist_cfg_file="$(pwd)/CustomBlackListPropertiesConfig.cfg"
custom_blacklist_cfg_tmp_file="$(pwd)/TmpCustomBlackListPropertiesConfig.cfg"
# 屬性前綴,屬性前綴需要特殊處理
class_prefix=""
# 屬性后綴
class_suffix="abc"


# 檢測(cè)文件是否存在,不存在則創(chuàng)建
checkOrCreateFile() {
	file=$1
	if [[ -f $file ]]; then
		echo "檢測(cè)到配置文件存在 $file"
	else
		echo "創(chuàng)建配置文件 $file"
		touch $file
	fi
}

# 配置文件檢查
checkOrCreateFile $cfg_file

# 循環(huán)檢測(cè)輸入的文件夾
function checkInputDestDir {
	echo -n "請(qǐng)輸入需處理源碼目錄: "
	read path
	if [[ -d $path ]]; then
		classes_dir=$path
	else
		echo -n "輸入的目錄無效,"
		checkInputDestDir
	fi
}

# 需處理源碼目錄檢查
if [[ -d $classes_dir ]]; then
	echo "需處理源碼目錄存在 $classes_dir"
else
	echo "請(qǐng)確認(rèn)需處理源碼目錄是否存在 $classes_dir"
	checkInputDestDir
fi


####### 數(shù)據(jù)定義

# 定義屬性保存數(shù)組
declare -a rename_properties_config_content_array
cfg_line_count=0


# 讀取屬性配置文件
function read_rename_properties_configs {
	IFS_OLD=$IFS
	IFS=$'\n'
	# 刪除文件行首的空白字符 http://www.dbjr.com.cn/article/57972.htm
	for line in $(cat $cfg_file | sed 's/^[ \t]*//g')
	do
		is_comment=$(expr "$line" : '^#.*')
		echo "line=${line} is_common=${is_comment}"
		if [[ ${#line} -eq 0 ]] || [[ $(expr "$line" : '^#.*') -gt 0 ]]; then
			echo "blank line or comment line"
		else
			rename_properties_config_content_array[$cfg_line_count]=$line
			cfg_line_count=$[ $cfg_line_count + 1 ]
			# echo "line>>>>${line}"
		fi	
	done
	IFS=${IFS_OLD}
}

function print_array {
	# 獲取數(shù)組
	local newarray
	newarray=($(echo "$@"))
	for (( i = 0; i < ${#newarray[@]}; i++ )); do
		item=${newarray[$i]}
		echo "array item >>> ${item}"
	done
}

# 重命名所有的屬性
function rename_properties {

	# 讀取屬性配置文件
	read_rename_properties_configs
	# print_array ${rename_properties_config_content_array[*]}

	# 執(zhí)行替換操作
	for (( i = 0; i < ${#rename_properties_config_content_array[@]}; i++ )); do
		original_prop_name=${rename_properties_config_content_array[i]};
		result_prop_name="${class_prefix}${original_prop_name}${class_suffix}"
		sed -i '{
			s/'"${original_prop_name}"'/'"${result_prop_name}"'/g
		}' `grep ${original_prop_name} -rl ${classes_dir}`
		echo "正在處理屬性 ${original_prop_name}....."
	done
}

checkOrCreateFile ${custom_blacklist_cfg_tmp_file}

# 獲取自定義的黑名單屬性并保存到文件中
echo "" > ${custom_blacklist_cfg_file}
for (( i = 0; i < ${#custom_blacklist_search_dirs[@]}; i++ )); do
	custom_blacklist_search_dir=${custom_blacklist_search_dirs[${i}]}
	./GetAndStoreProperties.sh \
		-i ${custom_blacklist_search_dir}\
		-o ${custom_blacklist_cfg_tmp_file}
	cat ${custom_blacklist_cfg_tmp_file} >> ${custom_blacklist_cfg_file}
done


# 獲取和保存屬性到熟悉配置文件
./GetAndStoreProperties.sh \
	-i ${classes_dir}\
	-o ${cfg_file}\
	-f \
	-c ${custom_blacklist_cfg_file}


# 執(zhí)行屬性重命名
rename_properties

echo "done."

總結(jié)

以上就是基于shell腳本,以殼版本為場景,把屬性的批量替換做了一個(gè)半自動(dòng)化的實(shí)現(xiàn)步驟,如果不妥之處,還請(qǐng)不吝賜教。

相關(guān)文章

  • Objective-C 宏定義詳細(xì)介紹

    Objective-C 宏定義詳細(xì)介紹

    這篇文章主要介紹了Objective-C 宏定義詳細(xì)介紹的相關(guān)資料,這樣開發(fā)起來,更有效率,更好,更簡潔,需要的朋友可以參考下
    2016-10-10
  • iOS自定義日期、時(shí)間、城市選擇器實(shí)例代碼

    iOS自定義日期、時(shí)間、城市選擇器實(shí)例代碼

    這篇文章主要介紹了iOS自定義日期、時(shí)間、城市選擇器實(shí)例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-05-05
  • ios通過SDWebImage實(shí)現(xiàn)圖片加載時(shí)的漸變效果

    ios通過SDWebImage實(shí)現(xiàn)圖片加載時(shí)的漸變效果

    本篇文章主要介紹了ios通過SDWebImage實(shí)現(xiàn)圖片加載時(shí)的漸變效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • iOS導(dǎo)航欄對(duì)控制器view的影響詳解

    iOS導(dǎo)航欄對(duì)控制器view的影響詳解

    這篇文章主要給大家介紹了關(guān)于iOS導(dǎo)航欄對(duì)控制器view的影響的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)各位iOS開發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • IOS開發(fā)相冊(cè)圖片多選和刪除的功能

    IOS開發(fā)相冊(cè)圖片多選和刪除的功能

    之前小編有和大家分享過一篇關(guān)于從相冊(cè)選取單張照片的文章,那么下面這篇文章跟大家分享下如何相冊(cè)多圖選擇和刪除,以及包括拍照功能,有需要的可以參考學(xué)習(xí),下面來一起看看吧。
    2016-09-09
  • iOS實(shí)現(xiàn)垂直滑動(dòng)條效果

    iOS實(shí)現(xiàn)垂直滑動(dòng)條效果

    這篇文章主要為大家詳細(xì)介紹了iOS實(shí)現(xiàn)垂直滑動(dòng)條效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • iOS推送之本地通知UILocalNotification

    iOS推送之本地通知UILocalNotification

    這篇文章主要為大家詳細(xì)介紹了iOS本地通知UILocalNotification,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-09-09
  • 詳解iOS的深淺拷貝

    詳解iOS的深淺拷貝

    本文詳細(xì)介紹了IOS中的三種拷貝方式,對(duì)iOS的深淺拷貝有疑問的朋友們可以參考下本文。
    2016-08-08
  • iOS實(shí)現(xiàn)簡易鐘表

    iOS實(shí)現(xiàn)簡易鐘表

    這篇文章主要為大家詳細(xì)介紹了iOS實(shí)現(xiàn)簡易鐘表,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-02-02
  • IOS 通過tag刪除動(dòng)態(tài)創(chuàng)建的UIButton

    IOS 通過tag刪除動(dòng)態(tài)創(chuàng)建的UIButton

    這篇文章主要介紹了IOS 通過tag刪除動(dòng)態(tài)創(chuàng)建的UIButton的相關(guān)資料,需要的朋友可以參考下
    2017-03-03

最新評(píng)論