iOS巨集和__attribute__

来源:http://www.cnblogs.com/Mike-zh/archive/2016/01/20/5143904.html
-Advertisement-
Play Games

本文目錄 1. iOS巨集的經典用法 2. Apple的習慣3. \_\_attribute\_\_ iOS巨集的經典用法 1.常量巨集、表達式巨集 2.帶參數的巨集 3.函數巨集(是一個沒有返回值的代碼塊,通常當做一行語句使用) 4.內聯函數 (一般有返回值) 5.變參巨集 函數可變參數 關於巨集定義...


本文目錄

  1. iOS巨集的經典用法
  2. Apple的習慣
  3. __attribute__

iOS巨集的經典用法

1.常量巨集、表達式巨集

#define kTabBarH (49.0f)
#define kScreenH [UIScreen mainScreen].bounds.size.height
#define isScreenWidthEqual320 (fabs([UIScreen mainScreen].bounds.size.width - 320) < DBL_EPSILON)

2.帶參數的巨集

// 例子1:同樣是一個表達式
#define isNilOrNull(obj) (obj == nil || [obj isEqual:[NSNull null]])
// 例子2:也可以沒有參數值 使用的時候要加上"()",是在使用的時候單獨成為一行語句的巨集
#define MKAssertMainThread() NSAssert([NSThread isMainThread], @"This method must be called on the main thread")

3.函數巨集(是一個沒有返回值的代碼塊,通常當做一行語句使用)

// do {} while(0) 一般是沒有返回值的,僅僅是代碼塊而已
#define NSAssert(condition, desc, ...)  \
    do {                \
    __PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS \
    if (!(condition)) {     \
            NSString *__assert_file__ = [NSString stringWithUTF8String:__FILE__]; \
            __assert_file__ = __assert_file__ ? __assert_file__ : @"<Unknown File>"; \
        [[NSAssertionHandler currentHandler] handleFailureInMethod:_cmd \
        object:self file:__assert_file__ \
            lineNumber:__LINE__ description:(desc), ##__VA_ARGS__]; \
    }               \
        __PRAGMA_POP_NO_EXTRA_ARG_WARNINGS \
    } while(0)

4.內聯函數 (一般有返回值)

CG_INLINE CGRect
CGRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height)
{
  CGRect rect;
  rect.origin.x = x; rect.origin.y = y;
  rect.size.width = width; rect.size.height = height;
  return rect;
}

NS_INLINE BOOL 
MKIsLeapYear() {
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSInteger year = [calendar component:NSCalendarUnitYear fromDate:[NSDate new]];
    return year % 100 == 0 ? year % 400 == 0 : year % 4 == 0;
}

5.變參巨集 函數可變參數

// 例如可以像如下幾種方式使用NSAssert這個巨集
NSAssert(10 > 11, @"錯誤1:%@", @"err desc 1");
NSAssert(10 > 11, @"錯誤1:%@\n錯誤2:%@", @"err desc 1", @"err desc 2");

關於巨集定義中的#和##的說明
#有兩個作用:
1.將變數直接轉化為相應字面量的C語言字元串 如a=10 #a會轉化為"10"
2.連接兩個C字元串,使用如下

#define toString(a) #a  // 轉為字元串
#define printSquare(x) printf("the square of "  #x " is %d.\n",(x)*(x)) // 連接字元串

使用如下

printf("%s\n", toString(abc)); // abc
printSquare(3); // the square of 3 is 9.

##的常見用處是連接,它會將在它之前的語句、表達式等和它之後的語句表達式等直接連接。

// 用法1:代碼和表達式直接連接
#define combine(a, b) a##b 
#define exp(a, b) (long)(a##e##b)  
// 用法2:給表達式加首碼
#define addPrefixForVar(a) mk_##a 
// 用法3,用於連接printf-like方法的format語句和可變參數
#define format(format, ...) [NSString stringWithFormat:format, ##__VA_ARGS__]

使用示例如下:

NSLog(@"%zd", combine(10, 556)); // 10556
NSLog(@"%f", combine(10, .556)); // 10.556000
NSLog(@"%tu", exp(2, 3)); // 2000
    
// int x = 10;
int mk_x = 30;
NSLog(@"%d", addPrefixForVar(x));  // 30
    
NSLog(@"%@", format(@"%@_%@", @"good", @"morning"));  // good_morning
NSLog(@"%@", format(@"hello"));  // hello

對於使用##連接可變參數的用法,如果不加##會導致編譯無法通過,這是因為: ##後面的值不存在的時候 會忽略## 前面的,
也就是說:
當有## 調用format(format) 替換為 [NSString stringWithFormat:format]
當沒有## 調用format(format) 替換為 [NSString stringWithFormat:format ,]

還有一點要註意的是:###只能用在巨集定義中,而不能使用在函數或者方法中。

Apple使用巨集的一些習慣

1.類的聲明除了引用的其他頭文件 用下麵一對巨集標記
#define NS_ASSUME_NONNULL_BEGIN _Pragma("clang assume_nonnull begin")
#define NS_ASSUME_NONNULL_END   _Pragma("clang assume_nonnull end")

也可以使用下麵的兩句

#pragma clang assume_nonull begin
#pragma clang assume_nonull end

告訴clang編譯器這兩者之間內容非空

2. 在類聲明前,方法聲明後都有可用性的標記巨集

例如

NS_CLASS_AVAILABLE   // 類之前
NS_AVAILABLE(_mac, _ios) // 方法之後
NS_DEPRECATED(_macIntro, _macDep, _iosIntro, _iosDep, ...) // 方法之後
OBJC_SWIFT_UNAVAILABLE("use 'xxx' instead") // 針對swift特殊說明取代它的類和方法

不同功能的類之前的可用性標記不同,例如NSAutoreleasePool之前

NS_AUTOMATED_REFCOUNT_UNAVAILABLE
@interface NSAutoreleasePool : NSObject{ ...

對於這些標記究竟幹了些什麼,請看本文第三部分__attribute__。

3.嵌套的巨集(經常成對使用)
#define NS_DURING       @try {
#define NS_HANDLER      } @catch (NSException *localException) {
#define NS_ENDHANDLER       }
#define NS_VALUERETURN(v,t) return (v)
#define NS_VOIDRETURN       return


#if __clang__
#define __PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS \
    _Pragma("clang diagnostic push") \
    _Pragma("clang diagnostic ignored \"-Wformat-extra-args\"")

#define __PRAGMA_POP_NO_EXTRA_ARG_WARNINGS _Pragma("clang diagnostic pop")
#else
#define __PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS
#define __PRAGMA_POP_NO_EXTRA_ARG_WARNINGS
#endif
4.經常使用條件巨集 (為了適配當前的硬體環境,系統環境、語言環境、編譯環境)
#if !defined(NS_BLOCKS_AVAILABLE)
    #if __BLOCKS__ && (MAC_OS_X_VERSION_10_6 <= MAC_OS_X_VERSION_MAX_ALLOWED || __IPHONE_4_0 <= __IPHONE_OS_VERSION_MAX_ALLOWED)
        #define NS_BLOCKS_AVAILABLE 1
    #else
        #define NS_BLOCKS_AVAILABLE 0
    #endif
#endif


#if !defined(NS_NONATOMIC_IOSONLY)
    #if TARGET_OS_IPHONE
    #define NS_NONATOMIC_IOSONLY nonatomic
    #else
        #if __has_feature(objc_property_explicit_atomic)
            #define NS_NONATOMIC_IOSONLY atomic
        #else
            #define NS_NONATOMIC_IOSONLY
        #endif
    #endif
#endif


#if defined(__cplusplus)
#define FOUNDATION_EXTERN extern "C"
#else
#define FOUNDATION_EXTERN extern
#endif
5. 由__attribute__定義的巨集處處可見。

(本文在第三部分詳細介紹__attribute__.).
例如下麵這些常見的巨集都屬於這種:

// NSLog 方法後面使用的巨集
#define NS_FORMAT_FUNCTION(F,A) __attribute__((format(__NSString__, F, A)))


//  這些都是在<Foundation/NSObjCRuntime.h>中定義的巨集
#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
#define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained))
#define NS_RETURNS_INNER_POINTER __attribute__((objc_returns_inner_pointer))
#define NS_AUTOMATED_REFCOUNT_UNAVAILABLE __attribute__((unavailable("not available in automatic reference counting mode")))
#define NS_AUTOMATED_REFCOUNT_WEAK_UNAVAILABLE __attribute__((objc_arc_weak_reference_unavailable))
#define NS_REQUIRES_PROPERTY_DEFINITIONS __attribute__((objc_requires_property_definitions)) 
#define NS_REPLACES_RECEIVER __attribute__((ns_consumes_self)) NS_RETURNS_RETAINED
#define NS_RELEASES_ARGUMENT __attribute__((ns_consumed))
#define NS_VALID_UNTIL_END_OF_SCOPE __attribute__((objc_precise_lifetime))
#define NS_ROOT_CLASS __attribute__((objc_root_class))
#define NS_REQUIRES_SUPER __attribute__((objc_requires_super))
#define NS_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer))
#define NS_PROTOCOL_REQUIRES_EXPLICIT_IMPLEMENTATION __attribute__((objc_protocol_requires_explicit_implementation))
#define NS_CLASS_AVAILABLE(_mac, _ios) __attribute__((visibility("default"))) NS_AVAILABLE(_mac, _ios)
#define NS_CLASS_DEPRECATED(_mac, _macDep, _ios, _iosDep, ...) __attribute__((visibility("default"))) NS_DEPRECATED(_mac, _macDep, _ios, _iosDep, __VA_ARGS__)
#define NS_SWIFT_NOTHROW __attribute__((swift_error(none)))
#define NS_INLINE static __inline__ __attribute__((always_inline))
#define NS_REQUIRES_NIL_TERMINATION __attribute__((sentinel(0,1)))

而我們經常看到的這樣的幾個巨集

#define NS_AVAILABLE(_mac, _ios) CF_AVAILABLE(_mac, _ios)
#define NS_AVAILABLE_MAC(_mac) CF_AVAILABLE_MAC(_mac)
#define NS_AVAILABLE_IOS(_ios) CF_AVAILABLE_IOS(_ios)

被定義在了<CoreFoundation/CFAvailability.h>中

#define CF_AVAILABLE(_mac, _ios) __attribute__((availability(macosx,introduced=_mac)))
#define CF_AVAILABLE_MAC(_mac) __attribute__((availability(macosx,introduced=_mac)))
#define CF_AVAILABLE_IOS(_ios) __attribute__((availability(macosx,unavailable)))

總之你會發現只要是不具備表達式或者代碼塊功能的巨集,絕大多數都是由__attribute__定義的,那麼__attribute__到底是什麼呢,請繼續:

__attribute__

GNU C 的一大特色就是__attribute__機制。__attribute__可以設置函數屬性(Function Attribute )、變數屬性(Variable Attribute )和類型屬性(Type Attribute )。
__attribute__的書寫方式是:__attribute__後面會緊跟一對原括弧,括弧裡面是相應的__attribute__參數,格式如:
__attribute__((attribute-list))
其位置約束為:放於聲明的尾部“;” 之前。
那麼現在的問題就是什麼情況下使用__attribute__,以及如何設置參數attribute-list,主要分為三種情況:
函數屬性(Function Attribute )、變數屬性(Variable Attribute )和類型屬性(Type Attribute )。

1.函數屬性(Function Attribute )

函數屬性可以幫助開發者把一些特性添加到函數聲明中,從而可以使編譯器在錯誤檢查方面的功能更強大。__attribute__機制也很容易同非GNU應用程式做到相容之功效。

__attribute__((format))

例如NSLog聲明中使用到的巨集:

#define NS_FORMAT_FUNCTION(F,A) __attribute__((format(__NSString__, F, A)))

__attribute__((format(__NSString__, F, A)))

該__attribute__屬性可以給被聲明的函數加上類似printf或者scanf的特征,它可以使編譯器檢查函數聲明和函數實際調用參數之間的格式化字元串是否匹配。該功能十分有用,尤其是處理一些很難發現的bug。對於format參數的使用如下
format (archetype, string-index, first-to-check)
第一參數需要傳遞“archetype”指定是哪種風格;“string-index”指定傳入函數的第幾個參數是格式化字元串;“first-to-check”指定第一個可變參數所在的索引。
如NSLog對這個巨集的使用如下:

FOUNDATION_EXPORT void NSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);

那麼它如何進行語法檢查,看下麵的例子:

extern void myPrint(const char *format,...)__attribute__((format(printf,1,2)));

void test() {
    myPrint("i=%d\n",6);
    myPrint("i=%s\n",6);
    myPrint("i=%s\n","abc");
    myPrint("%s,%d,%d\n",1,2);
}

使用clang命令編譯一下:

clang -c main.m

結果會出現下麵的警告

main.m:70:22: warning: format specifies type 'char *' but the argument has type 'int' [-Wformat]
    myPrint("i=%s\n",6);
               ~~    ^
               %d
main.m:72:26: warning: format specifies type 'char *' but the argument has type 'int' [-Wformat]
    myPrint("%s,%d,%d\n",1,2);
             ~~          ^
             %d
main.m:72:21: warning: more '%' conversions than data arguments [-Wformat]
    myPrint("%s,%d,%d\n",1,2);
                   ~^
3 warnings generated.

如果將
__attribute__((format(printf,1,2)))直接去掉,再次編譯,則不會有任何警告。

__attribute__((noreturn))

該屬性通知編譯器函數從不返回值。當遇到類似函數還未運行到return語句就需要退出來的情況,該屬性可以避免出現錯誤信息。C庫函數中的abort()和exit()的聲明格式就採用了這種格式。使用如下:

void fatal () __attribute__ ((noreturn));
          
void fatal (/* ... */) {
   /* ... */ 
   /* Print error message. */ 
   /* ... */
   exit (1);
}
__attribute__((constructor/destructor))

若函數被設定為constructor屬性,則該函數會在main()函數執行之前被自動的執行。類似的,若函數被設定為destructor屬性,則該 函數會在main()函數執行之後或者exit()被調用後被自動的執行。擁有此類屬性的函數經常隱式的用在程式的初始化數據方面。
例如:

static __attribute__((constructor)) void before() {
    
    printf("Hello");
}

static __attribute__((destructor)) void after() {
    printf(" World!\n");
}
int main(int argc, const char * argv[]) {
    printf("0000");
    return 0;
}

程式輸出結果是:

Hello0000 World!

如果多個函數使用了這個屬性,可以為它們設置優先順序來決定執行的順序:

__attribute__((constructor(PRIORITY)))
__attribute__((destructor(PRIORITY)))

如:

static __attribute__((constructor(101))) void before1() {
    printf("before1\n");
}

static __attribute__((constructor(102))) void before2() {
    printf("before2\n");
}

static __attribute__((destructor(201))) void after1() {
    printf("after1\n");
}

static __attribute__((destructor(202))) void after2() {
    printf("after2\n");
}
int main(int argc, const char * argv[]) {
    printf("0000\n");
    return 0;
}

輸出的結果是:

before1
before2
0000
after2
after1

從輸出的信息看,前處理都是按照優先順序先後執行的,而後處理則是相反的.
需要註意的是:優先順序是有範圍的。0-100(包括100),是內部保留的,所以在編碼的時候需要註意.
另外一個註意的點是,上面的函數沒有聲明而是直接實現這樣__attribute__就需要放到前面,應該多使用函數聲明和實現分離的方法:

static void before1() __attribute__((constructor(1)));

static void before1() {
    printf("before1\n");
}

其他的函數屬性(Function Attribute )還有:noinline, always_inline, pure, const, nothrow, sentinel, format, format_arg, no_instrument_function, section, constructor, destructor, used, unused, deprecated, weak, malloc, alias, warn_unused_result, nonnull等等,可以參考 GNU C的文檔查看它們的具體使用方法。

如何同時使用多個屬性:
可以在同一個函數聲明裡使用多個__attribute__,並且實際應用中這種情況是十分常見的。只需要把它們用','隔開就可以,如:

 __attribute__((noreturn, format(printf, 1, 2)))

2.類型屬性 (Type Attributes)

__attribute__ aligned

該屬性設定一個指定大小的對齊格式(以位元組 為單位),例如:

struct S {
    short f[3];
} __attribute__ ((aligned (8)));

typedef int more_aligned_int __attribute__ ((aligned (8)));

該聲明將強制編譯器確保(盡它所能)變數類型為struct S 或者more_aligned_int的變數在分配空間時採用至少8位元組對齊方式。
如上所述,你可以手動指定對齊的格式,同樣,你也可以使用預設的對齊方式。如果aligned 後面不緊跟一個指定的數字值,那麼編譯器將依據你的目標機器情況使用最大最有益的對齊方式。例如:

struct S {
    short f[3];
} __attribute__ ((aligned));

這裡,如果sizeof(short)的大小為2(byte),那麼,S的大小就為6。取一個2的次方值,使得該值大於等於6,則該值為8,所以編譯器將設置S類型的對齊方式為8位元組。
aligned 屬性使被設置的對象占用更多的空間,相反的,使用packed 可以減小對象占用的空間。
需要註意的是,attribute屬性的效力與你的連接器也有關,如果你的連接器最大隻支持16位元組對齊,那麼你此時定義32 位元組對齊也是無濟於事的。

__attribute__ packed

使用該屬性對struct或者union類型進行定義,設定其類型的每一個變數的記憶體約束。當用在enum類型定義時,暗示了應該使用最小完整的類型(it indicates that the smallest integral type should be used)。

下麵的例子中,packed_struct 類型的變數數組中的值將會緊緊的靠在一起,但內部的成員變數s不會被“pack” ,如果希望內部的成員變數也被packed 的話,unpacked-struct也需要使用packed進行相應的約束。

struct my_unpacked_struct {
    char c;
    int i;
};

struct my_packed_struct {
    char c;
    int  i;
    struct my_unpacked_struct s;
}__attribute__ ((__packed__));

下麵的例子中使用這個屬性定義了一些結構體及其變數,並給出了輸出結果和對結果的分析。
程式代碼為:

struct p {
    int a;
    char b;
    short c;
}__attribute__((aligned(4))) pp;

struct m {
    char a;
    int b;
    short c;
}__attribute__((aligned(4))) mm;

struct o {
    int a;
    char b;
    short c;
}oo;

struct x {
    int a;
    char b;
    struct p px;
    short c;
}__attribute__((aligned(8))) xx;
int main() {
    printf("sizeof(int)=%d,sizeof(short)=%d.sizeof(char)=%d\n",sizeof(int),sizeof(short),sizeof(char));
    printf("pp=%d,mm=%d \n", sizeof(pp),sizeof(mm));
    printf("oo=%d,xx=%d \n", sizeof(oo),sizeof(xx));
    return 0;
}

輸出結果為:

sizeof(int)=4,sizeof(short)=2.sizeof(char)=1
pp=8,mm=12 
oo=8,xx=24 

分析:
1.sizeof(pp):
sizeof(a)+sizeof(b)+sizeof(c)=4+1+1=6<8 所以sizeof(pp)=8

2.sizeof(mm):
sizeof(a)+sizeof(b)+sizeof(c)=1+4+2=7
但是a後面需要用3個位元組填充,但是b是4個位元組,所以a占用4位元組,b占用4 個位元組,而c又要占用4個位元組。所以sizeof(mm)=12

3.sizeof(oo):
sizeof(a)+sizeof(b)+sizeof(c)=4+1+2=7
因為預設是以4位元組對齊,所以sizeof(oo)=8

4.sizeof(xx):
sizeof(a)+ sizeof(b)=4+1=5
sizeof(pp)=8; 即xx是採用8位元組對齊的,所以要在a,b後面添3個空餘位元組,然後才能存儲px,
4+1+(3)+8+1=17
因為xx採用的對齊是8位元組對齊,所以xx的大小必定是8的整數倍,即xx的大小是一個比17大又是8的倍數的一個最小值,17<24,所以sizeof(xx)=24.

其他的函數屬性(Function Attribute )還有:aligned, packed, transparent_union, unused, deprecated and may_alias等等,可以參考GNU C的文檔查看它們的具體使用方法。

3.變數屬性 (Variable Attribute)

變數屬性最常用的是aligned和packed其他的用法請參考 GNU C的文檔

4.Clang特有的__attribute__

如同GCC編譯器, Clang也支持 __attribute__, 而且對它進行的一些擴展.
如果要檢查指定屬性的可用性,你可以使用__has_attribute指令。
下麵介紹一些clang特有的attribute

availability

該屬性描述了方法關於操作系統版本的適用性, 使用如下:

(void) __attribute__((availability(macosx,introduced=10.4,deprecated=10.6,obsoleted=10.7)));

他表示被修飾的方法在首次出現在 OS X Tiger(10.4),在OS X Snow Leopard(10.6)中廢棄,在 OS X Lion(10.7)移除。
clang可以利用這些信息決定什麼時候使用它使安全的。比如:clang在OS X Leopard()編譯代碼,調用這個方法是成功的,如果在OS X Snow Leopard編譯代碼,調用成功但是會發出警告指明這個方法已經廢棄,如果是在OS X Lion,調用會失敗,因為它不再可用。
availability屬性是一個以逗號為分隔的參數列表,以平臺的名稱開始,包含一些放在附加信息里的一些里程碑式的聲明。
introduced:第一次出現的版本。
deprecated:聲明要廢棄的版本,意味著用戶要遷移為其他API
obsoleted:聲明移除的版本,意味著完全移除,再也不能使用它
unavailable:在這些平臺不可用
message:一些關於廢棄和移除的額外信息,clang發出警告的時候會提供這些信息,對用戶使用替代的API非常有用。
這個屬性支持的平臺:
ios,macosx。

overloadable

clang 在C語言中實現了對C++函數重載的支持,使用overloadable屬性可以實現。例如:

#include <math.h>
float __attribute__((overloadable)) tgsin(float x) { return sinf(x); }
double __attribute__((overloadable)) tgsin(double x) { return sin(x); }
long double __attribute__((overloadable)) tgsin(long double x) { return sinl(x); }

要註意的是overloadable僅僅對函數有效, 你可以重載方法,不過範圍局限於返回值和參數是常規類型的如:id和void *。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 隨著CSS3和HTML5的流行,我們的WEB頁面不僅需要更人性化的設計理念,而且需要更酷的頁面特效和用戶體驗。作為開發者,我們需要瞭解一些寶貴的CSS UI開源框架資源,它們可以幫助我們更快更好地實現一些現代化的界面,包括一些移動設備的網頁界面風格設計。本文分享了10個頂級的CSS UI開源框架,有...
  • UIView 不像 UIButton 加了點擊事件就會有點擊效果,體驗要差不少,這裡分別通過自定義和擴展來實現類似 UIButton 的效果。
  • 一、android序列化簡介我們已經知道在Android使用Intent/Bindler進行IPC傳輸數據時,需要將對象進行序列化。JAVA原本已經提供了Serializable介面來實現序列化,使用起來非常簡單,主要用於對象持久化以及對象的網路傳輸。Serializable開銷比較大,因為序列化和...
  • 適配器模式的定義:將一個類的介面,轉換成客戶期望的另一個介面。適配器讓原本介面不相容的類可以合作無間。 適配器模式其實也可以叫做轉換器模式,由定義可知適配器其實就是包裝某些對象從而讓他們的幾口開起來不像自己而像是別的東西。舉一個簡單的例子 : 假設現在已有一個軟體系統,你希望它能和一個新的廠...
  • 1:動畫屬性UIViewAnimationOptions說明a:常規動畫屬性設置(可以同時選擇多個進行設置)UIViewAnimationOptionLayoutSubviews:動畫過程中保證子視圖跟隨運動。UIViewAnimationOptionAllowUserInteraction:動畫過...
  • 效果圖1 string.xmlDefault Progressbar:2 attrs.xml 3 activity_main....
  • 源碼測試示例:package com.example.popupwindown;import android.os.Bundle;import android.app.Activity;import android.view.Gravity;import android.view.Menu;impo...
  • 一,效果圖。二,工程圖。三,代碼。RootViewController.h#import @interface RootViewController : UIViewController{ UITableView *myTableView;}@endRootViewController.m#i...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...